Thư viện async
gói gọn một vài mẫu không đồng bộ rất phổ biến, trong đó có thực hiện cuộc gọi async tùy ý song song và lặp qua danh sách không đồng bộ. Nó được thiết kế để hoạt động với các API "nodeback" (err, res)
, điều này giúp ích cho rất nhiều ứng dụng Node.js. Tuy nhiên, async
là giải pháp cụ thể và chỉ đơn giản hóa các mẫu không đồng bộ được bao gồm trong thư viện.
Câu trả lời, ngược lại, theo ý kiến của tôi, giải pháp chung chung hơn về vấn đề mã không đồng bộ. Không chỉ cung cấp cho họ những lợi ích rõ ràng ngay từ cái nhìn đầu tiên về lỗi sủi bọt và kim tự tháp gọi lại phẳng, những vấn đề có thể đòi hỏi các kiểu phức tạp hơn.
Tôi sẽ minh họa điều này bằng cách tham quan nhanh qua một số mẫu có sẵn của async
. Ví dụ, async.waterfall
chức năng được sử dụng một cái gì đó như thế này:
async.waterfall([
function (cb) {
asyncCall('argument', cb);
},
function(resultOfFirstCall, cb) {
anotherCall(resultOfFirstCall, 'someOtherArgument' cb);
},
], function(err, res) {
if (err) handle(err);
useFinalResult(res);
});
Không có tương đương với async.waterfall
trong hầu hết các thư viện lời hứa (hoặc ít nhất là không có một trong Q), bởi vì nó đơn giản như vậy để thực hiện nó từ đầu sử dụng Array.reduce
, như vậy (ví dụ dựa trên Q nhưng khá nhiều giống nhau trên thư viện lời hứa khác):
[
function() {
return asyncCall('argument');
},
function(resultOfFirstCall) {
return anotherCall(resultOfFirstCall, 'someOtherArgument');
}
].reduce(Q.when, Q())
.then(useFinalResult, handle);
các chức năng lớn khác trong async
bao gồm async.parallel
, mà Q bao gồm như Q.all
:
// async
async.parallel([
asyncFunc,
asyncFunc2
], function(err, res) {
if (err) handle(err);
useFinalResult(res);
// res[0] === asyncFuncResult
// res[1] === asyncFunc2Result
});
// Q
Q.all([
asyncFunc(),
asyncFunc2()
]).then(useFinalResult, handle);
Và async.map
.Bạn thực sự không cầnasync.map
khi bạn đang sử dụng những lời hứa, bởi vì bình thường Array.map
là đủ:
// async
async.map(['file', 'file2', 'file3'], fs.stat, function(err, res) {
if (err) handle(err);
useFinalResult(res);
});
// Q
Q.all(['file', 'file2', 'file3']
.map(Q.nfbind(fs.stat)))
.then(useFinalResult, handle);
Phần còn lại của async
là dễ dàng tương tự để thực hiện chính xác, sử dụng mảnh tương đối đơn giản của thư viện lời hứa của mình. (Lưu ý rằng ví dụ cuối cùng đã sử dụng hàm Q.nfbind
: nfbind
và các hàm nf*
Q khác về cơ bản là tất cả những gì bạn cần để sử dụng lời hứa với API nodeback, vì vậy không có trở ngại lớn nào khi cố gắng sử dụng lời hứa với các thư viện Cuối cùng, cho dù bạn sử dụng lời hứa hoặc nodebacks là tùy thuộc vào bạn, nhưng tôi nghĩ lời hứa là một cách linh hoạt hơn, có khả năng và thường ngắn gọn hơn để thực hiện hầu hết các hoạt động không đồng bộ.
Callbacks are imperative, promises are functional đáng để đọc để biết thêm thông tin trong tĩnh mạch chung này.
Lợi thế chính của việc sử dụng thư viện async được liên kết là nó * kết thúc tốt đẹp/cung cấp * một số hoạt động phổ biến theo kiểu không đồng bộ. Trong khi "đồng bằng" [Promises] (http://wiki.commonjs.org/wiki/Promises/A) (tức là jQuery.Deferred) có thể được sử dụng, nó sẽ mất nhiều hơn nữa boilerplate (nếu một trong những hoạt động đó là mong muốn trong một phong cách async) khi bạn có hiệu quả phải viết các phiên bản của riêng bạn của các chức năng nói. Thư viện async được liên kết và Promises cuối cùng hoạt động theo cùng một cách - một * callback * được sử dụng. –
Điều tôi thích về lời hứa là bạn trả lại thứ gì đó từ một hàm, thay vì chấp nhận một cuộc gọi lại mà bạn sẽ gọi sau đó (đối với tôi nó giống như nói: Tôi không thể trả lại giá trị này cho bạn trong thời điểm này, nhưng tôi hứa với bạn rằng bạn sẽ nhận được một giá trị). Những gì tôi không thích là bạn phải vượt qua 2 chức năng, nhưng điều này sẽ được giải quyết khi EcmaScript Harmony sẽ sẵn sàng. Với thực tế là Task.js rất tuyệt vời, lời hứa thực sự là bằng chứng trong tương lai. Có lẽ sẽ rất thú vị khi phát triển một mô-đun để thu hẹp khoảng cách giữa lời hứa và lời gọi lại (một cái gì đó như không đồng bộ, nhưng trả lại lời hứa). –