2015-04-17 22 views
5

Tôi đang thử nghiệm máy phát điện ES6 với sự trợ giúp của babel và tôi gặp sự cố khi hiểu (hoặc nếu!) Tôi có thể sử dụng chức năng async dựa trên gọi lại hiệu quả để tạo ra trình lặp.Máy phát điện ES6: chuyển đổi callbacks thành vòng lặp

Giả sử tôi muốn có thể viết một hàm nhận một số url, tải xuống không đồng bộ và trả lại chúng ngay khi chúng được tải xuống. Tôi muốn để có thể viết một cái gì đó như sau:

let urls = ['http://www.google.com', 'http://www.stackoverflow.com' ]; 
for ({url, data} of downloadUrls(urls)) { 
    console.log("Content of url", url, "is"); 
    console.log(data); 
} 

Làm thế nào tôi có thể thực hiện downloadUrls? Lý tưởng nhất là tôi muốn để có thể viết như sau:

var downloadUrls = function*(urls) { 
    for(let url of urls) { 
     $.ajax(url).done(function(data) { 
      yield data; 
     }); 
    } 
}; 

Điều này tất nhiên không làm việc, kể từ '' năng suất '' đang được gọi bên trong một callback và không trực tiếp bên trong máy phát điện. Tôi có thể tìm thấy nhiều ví dụ trực tuyến về những người đang cố gắng giống nhau, họ là not much transparent), yêu cầu enabling browser/node flags hoặc sử dụng các tính năng/thư viện dành riêng cho nút. Thư viện gần nhất với những gì tôi cần có vẻ là task.js, nhưng tôi không thể có ngay cả ví dụ đơn giản nhất chạy trên Chrome hiện tại.

Có cách nào để có được hành vi dự định sử dụng các tính năng chuẩn và hiện tại, (Hiện tại tôi có thể sử dụng với các trình cắm như babel, nhưng không cần phải bật thêm cờ trên trình duyệt) hoặc tôi phải đợi async/await ?

+0

Giải thích trực tuyến chính xác không "minh bạch" đối với bạn như thế nào?Bài viết walsh david là một trong những bài hay nhất tôi đã đọc (nhưng bạn sẽ cần phải đọc toàn bộ chuỗi khóa học) – Bergi

+0

Dường như có liên quan: Đề xuất máy phát không đồng bộ https://github.com/jhusain/asyncgenerator (chưa được hỗ trợ ở bất kỳ đâu AFAIK). –

Trả lời

1

Có cách nào để có được những hành vi có ý định sử dụng các tính năng tiêu chuẩn và hiện

Vâng, những lời hứa sử dụng và máy phát điện. Nhiều thư viện hứa hẹn, và một số thư viện độc lập, có tính năng sử dụng máy phát điện "coroutines".

Nhưng lưu ý rằng you cannot mix iteration with asynchrony, bạn chỉ có thể sử dụng máy phát điện. Ví dụ của bạn dường như gây nhầm lẫn cho họ một chút - có vẻ như bạn mong đợi rằng vòng lặp for ({url, data} of downloadUrls(urls)) { hoạt động đồng bộ, điều này không thể hoạt động.

Tôi có phải đợi async/await không?

Không, bạn không phải đợi, Babel already supports them!

1

Dưới đây là một cách sạch để sử dụng một máy phát điện/iterator để san bằng mã không đồng bộ mà làm việc cho tôi trong Node.js:

var asyncProcedureGenerator1 = function*() { 
    var it = yield(0); //get a reference to the iterator 
    try { 
     var a = yield (asyncPart1.bind(it))(0); //call the function, set this = it 
     var b = yield (asyncPart2.bind(it))(a); 
     var c = yield (asyncPart3.bind(it))(b); 
     console.log("c = ", c); 
    } 
    catch(err) 
    { 
     console.log("Something went wrong: ", err); 
    } 
}; 

var runAsyncGenerator = function(generator) { 
    var asyncProcedureIterator = generator(); //create an iterator 
    asyncProcedureIterator.next(); //start the iterator 
    asyncProcedureIterator.next(asyncProcedureIterator); //pass a reference of the iterator to itself 
} 

var asyncPart1 = function(param1) { 
    var it = this; //the iterator will be equal to this. 
    console.log("Starting asyncPart1 with param1 = ", param1); 
    setTimeout(function() { 
     console.log("Done with asyncPart1"); 
     var returnValue = 42 + param1; 
     console.log("asyncPart1 returned ", returnValue); 
     it.next(returnValue); //when we are done, resume the iterator which has yielded to us. 
    },2000); 
}; 

var asyncPart2 = function(param1) { 
    var it = this; //the iterator will be equal to this. 
    console.log("Starting asyncPart2 with param1 = ", param1); 
    setTimeout(function() { 
     console.log("Done with asyncPart2"); 
     var returnValue = param1/2; 
     console.log("asyncPart2 returned ", returnValue); 
     //it.throw("Uh oh."); 

     it.next(returnValue); 

    },2000); 
}; 

var asyncPart3 = function(param1) { 
    var it = this; //the iterator will be equal to this. 
    console.log("Starting asyncPart3 with param1 = ", param1); 
    setTimeout(function() { 
     console.log("Done with asyncPart3"); 
     var returnValue = param1/3; 
     console.log("asyncPart3 returned ", returnValue); 
     it.next(returnValue); 
    },2000); 
}; 

runAsyncGenerator(asyncProcedureGenerator1); 

Ý tưởng là để chạy máy phát điện, tạo một iterator, và sau đó vượt qua một tham chiếu của biến lặp đó cho chính nó. Sau đó, trình vòng lặp có thể gọi các hàm không đồng bộ (với lợi nhuận) và chuyển cho chúng tham chiếu đến chính nó, cho phép các hàm đó trả về thành công và tiếp tục thực hiện bằng cách gọi iterator.next (result) hoặc thất bại bằng cách gọi iterator.throw (lỗi).

Tôi vừa đưa ra mô hình này, vì vậy có thể có một số gotchas tôi chưa tìm thấy, nhưng có vẻ như nó hoạt động và cho phép mã rất bằng phẳng với các bổ sung tối thiểu.

Các vấn đề liên quan