Sự khác biệt giữa JavaScript hứa hẹn và không đồng bộ đang chờ đợi là gì?


97

Tôi đã sử dụng các tính năng ECMAScript 6 và ECMAScript 7 (nhờ Babel) trong các ứng dụng của tôi - cả di động và web.

Bước đầu tiên rõ ràng là ECMAScript 6 cấp độ. Tôi đã học được nhiều mẫu không đồng bộ, các hứa hẹn (thực sự hứa hẹn), trình tạo (không rõ tại sao ký hiệu *), v.v. Trong số này, các hứa hẹn phù hợp với mục đích của tôi khá tốt. Và tôi đã sử dụng chúng trong các ứng dụng của mình khá nhiều.

Đây là một ví dụ / mã giả về cách tôi đã triển khai một lời hứa cơ bản-

var myPromise = new Promise(
    function (resolve,reject) {
      var x = MyDataStore(myObj);
      resolve(x);
    });

myPromise.then(
  function (x) {
    init(x);
});

Khi thời gian trôi qua, tôi đi qua ECMAScript 7 tính năng, và một trong số đó ASYNCAWAITtừ khóa / chức năng. Những điều này kết hợp với nhau làm nên những điều kỳ diệu. Tôi đã bắt đầu thay thế một số lời hứa của mình bằng async & await. Chúng dường như thêm giá trị lớn cho phong cách lập trình.

Một lần nữa, đây là một mã giả về cách hàm async, await của tôi trông như thế nào-

async function myAsyncFunction (myObj) {
    var x = new MyDataStore(myObj);
    return await x.init();
}
var returnVal = await myAsyncFunction(obj);

Bỏ các lỗi cú pháp (nếu có) sang một bên, cả hai đều làm giống nhau là điều tôi cảm thấy. Tôi gần như đã có thể thay thế hầu hết các lời hứa của mình bằng async, đang chờ.

Tại sao không cần đồng bộ hóa, chờ đợi khi các lời hứa thực hiện một công việc tương tự?

Không đồng bộ hóa, chờ đợi có giải quyết được vấn đề lớn hơn không? Hay đó chỉ là một giải pháp khác để gọi lại địa ngục?

Như tôi đã nói trước đó, tôi có thể sử dụng các hứa hẹn và không đồng bộ, đang chờ giải quyết vấn đề tương tự. Có điều gì cụ thể mà async đang chờ giải quyết không?

Ghi chú bổ sung:

Tôi đã sử dụng async, chờ đợi và hứa hẹn trong các dự án React và các mô-đun Node.js của tôi một cách rộng rãi. Đặc biệt React đã là một con chim đầu đàn và được áp dụng rất nhiều tính năng ECMAScript 6 và ECMAScript 7.


3
Khối mã đầu tiên của bạn dường như sử dụng một lời hứa cho một hoạt động đồng bộ. Tại sao bạn lại làm vậy? Đồng bộ, về bản chất, dễ viết mã hơn vì vậy không có lý do gì để đưa một hoạt động đồng bộ vào một lời hứa và buộc nó bây giờ là không đồng bộ.
jfriend00 21/12/15

@ jfriend00 Vâng, bạn nói đúng. Đã chỉnh sửa mã. Cảm ơn.
bozzmob

2
Bạn vẫn đang cố gắng sử dụng các công cụ không đồng bộ với các chức năng đồng bộ - hiện có trong cả hai khối mã. Tại sao?
jfriend00

@ jfriend00 Ok. Ở đây tôi có mã gist.github.com/bozzmob/26d38b83dc37d1be37f5 . Xin vui lòng cho tôi biết tôi đang làm gì sai?
bozzmob

10
Có vẻ như bạn chỉ cần đọc một loạt để hiểu async và chờ đợi là gì. Dưới đây là một số điều: Con đường dài để Async / chờ đợi trong JavaScriptđơn giản hóa không đồng bộ Mã hóa với chức năng ES7 AsyncTaming the Beast không đồng bộ với ES7 .
jfriend00

Câu trả lời:


75

Tại sao không đồng bộ, cần chờ đợi khi Promises thực hiện công việc tương tự? Không đồng bộ hóa, chờ đợi có giải quyết được vấn đề lớn hơn không?

async/awaitchỉ đơn giản là mang lại cho bạn cảm giác đồng bộ với mã không đồng bộ. Đó là một dạng đường cú pháp rất tao nhã.

Đối với các truy vấn đơn giản và thao tác dữ liệu, Promises có thể đơn giản, nhưng nếu bạn gặp phải các tình huống có thao tác dữ liệu phức tạp và những gì không liên quan, sẽ dễ hiểu hơn chuyện gì đang xảy ra nếu mã đơn giản trông như thể nó đồng bộ (nói một cách khác, cú pháp tự nó là một dạng "phức tạp ngẫu nhiên" async/awaitcó thể xoay quanh).

Nếu bạn muốn biết, bạn có thể sử dụng một thư viện như co(cùng với máy phát điện) để mang lại cảm giác tương tự. Những thứ như thế này đã được phát triển để giải quyết vấn đề mà async/awaitcuối cùng sẽ giải quyết được (nguyên bản).


Bạn có thể giải thích thêm về "sự phức tạp ngẫu nhiên" có nghĩa là gì? Ngoài ra, khi nói đến hiệu suất, không có sự khác biệt giữa hai?
bozzmob

@bozzmob, shaffner.us/cs/papers/tarpit.pdf <- anh ấy giải thích "sự phức tạp ngẫu nhiên" trong đó. Theo như câu hỏi về hiệu suất của bạn, tôi nghi ngờ điều đó, đặc biệt là với động cơ V8. Tôi chắc chắn rằng có một số bài kiểm tra hiệu suất ở đó, nhưng tôi sẽ không lo lắng về điều đó quá nhiều. Đừng lãng phí thời gian của bạn vào việc tối ưu hóa vi mô khi không cần thiết.
Josh Beam

1
Cảm ơn rất nhiều! Đây là một số thông tin tuyệt vời mà tôi có được từ bạn. Và có, sẽ không xem xét các tối ưu hóa vi mô.
bozzmob

Tôi thấy điều này giải thích hữu ích nikgrozev.com/2015/07/14/...
mwojtera

33

Async / Await cung cấp một cú pháp đẹp hơn nhiều trong các tình huống phức tạp hơn. Đặc biệt, bất kỳ thứ gì liên quan đến vòng lặp hoặc một số cấu trúc khác như try/ catch.

Ví dụ:

while (!value) {
  const intermediate = await operation1();
  value = await operation2(intermediate);
}

Ví dụ này sẽ phức tạp hơn đáng kể nếu chỉ sử dụng Promises.


Đây là một ví dụ tuyệt vời để hiểu tương tự. Vì vậy, khi nói đến hiệu suất, không có sự khác biệt giữa hai? Và cái nào tốt hơn để sử dụng trong mã? Async Await có vẻ tốt hơn sau khi xem ví dụ của bạn ít nhất.
bozzmob

1
@bozzmob: Không có sự khác biệt về hiệu suất. Nếu bạn thấy thoải mái khi sử dụng async / await, thì tôi khuyên bạn nên sử dụng nó. Bản thân tôi chưa sử dụng nó vì nó không thực sự là một phần của tiêu chuẩn chính thức.
Stephen Cleary

Vâng, tôi đồng ý rằng nó không phải là một phần của tiêu chuẩn, nhưng, trong trường hợp của ReactJS (đặc biệt là react native), tôi buộc phải sử dụng nó ở một số phần của mã. Vì vậy, một nửa trong số đó là lời hứa và một nửa là không chờ đợi. Vì vậy, tôi đã hỏi bạn những câu hỏi đó. Cảm ơn vì những thông tin cần thiết.
bozzmob

1
Tôi nghĩ rằng rất nhiều người đã nhầm lẫn và / hoặc nhầm lẫn khi không ai sử dụng khối try / catch trong các mẫu mã của họ.
Augie Gardner

Ý bạn là như thế? const getValue = value => value || operation1().then(operation2).then(getValue);
Sharcoux

13

Tại sao không đồng bộ, cần chờ đợi khi Promises thực hiện công việc tương tự? Không đồng bộ hóa, chờ đợi có giải quyết được vấn đề lớn hơn không? hay đó chỉ là một giải pháp khác để gọi lại địa ngục? Như tôi đã nói trước đó, tôi có thể sử dụng Promises và Async, Await để giải quyết vấn đề tương tự. Có điều gì cụ thể mà Async Await đã giải quyết không?

Điều đầu tiên bạn phải hiểu rằng async/ awaitcú pháp chỉ là một đường cú pháp được dùng để tăng cường lời hứa. Trong thực tế, giá trị trả về của một asynchàm là một lời hứa. async/ awaitcú pháp cho chúng ta khả năng viết bất đồng bộ theo cách đồng bộ. Đây là một ví dụ:

Chuỗi hứa hẹn:

function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}

Async chức năng:

async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}

Trong ví dụ trên, awaitđợi cho lời hứa ( fetch(url)) được giải quyết hoặc bị từ chối. Nếu lời hứa được giải quyết, giá trị được lưu trữ trong responsebiến và nếu lời hứa bị từ chối, nó sẽ tạo ra một lỗi và do đó nhập vào catchkhối.

Chúng ta đã có thể thấy rằng việc sử dụng async/ awaitcó thể dễ đọc hơn so với chuỗi lời hứa. Điều này đặc biệt đúng khi số lượng lời hứa mà chúng ta đang sử dụng tăng lên. Cả chuỗi Promise và async/ awaitgiải quyết vấn đề địa ngục gọi lại và phương pháp bạn chọn là vấn đề sở thích cá nhân.


7

So sánh đầy đủ với ưu và nhược điểm.

JavaScript thuần túy

  • Ưu điểm
  • Không yêu cầu bất kỳ thư viện hoặc công nghệ bổ sung nào
  • Chúc bạn đạt được hiệu suất tốt nhất
  • Cung cấp mức độ tương thích tốt nhất với các thư viện của bên thứ ba
  • Cho phép tạo các thuật toán đặc biệt và nâng cao hơn
  • Nhược điểm
  • Có thể yêu cầu mã bổ sung và các thuật toán tương đối phức tạp

Async (thư viện)

  • Ưu điểm
  • Đơn giản hóa các mẫu điều khiển phổ biến nhất
  • Vẫn là một giải pháp dựa trên cuộc gọi lại
  • Hiệu suất tốt
  • Nhược điểm
  • Giới thiệu sự phụ thuộc bên ngoài
  • Có thể vẫn chưa đủ cho các khoản nâng cao

Lời hứa

  • Ưu điểm
  • Rất đơn giản hóa các mẫu điều khiển phổ biến nhất
  • Xử lý lỗi mạnh mẽ
  • Một phần của thông số ES2015
  • Bảo lãnh hoãn gọi onFulfilled và onRejected
  • Nhược điểm
  • Yêu cầu quảng bá các API dựa trên lệnh gọi lại
  • Giới thiệu một bản hit hiệu suất nhỏ

Máy phát điện

  • Ưu điểm
  • Làm cho API không chặn trông giống như một API chặn
  • Xử lý lỗi đơn giản
  • Một phần của thông số ES2015
  • Nhược điểm
  • Yêu cầu một thư viện điều khiển bổ sung
  • Vẫn yêu cầu gọi lại hoặc hứa hẹn để triển khai các lệnh không tuần tự
  • Yêu cầu thunkify hoặc công bố các API dựa trên nongenerator

Async đang chờ đợi

  • Ưu điểm
  • Làm cho API không chặn trông giống như chặn
  • Cú pháp rõ ràng và trực quan
  • Nhược điểm
  • Yêu cầu Babel hoặc các thiết bị chuyển âm khác và một số điều kiện hợp lệ để được sử dụng ngay hôm nay

Cái này được sao chép từ đâu? Ít nhất một số nó nằm trên trang 136-137 trong cuốn sách Các mẫu thiết kế Node.js (ấn bản thứ hai) (ISBN-10: 1785885588)
Peter Mortensen

6

Async / await có thể giúp làm cho mã của bạn sạch hơn và dễ đọc hơn trong những trường hợp bạn cần quy trình kiểm soát phức tạp. Nó cũng tạo ra mã thân thiện với gỡ lỗi hơn. Và làm cho nó có thể xử lý cả lỗi đồng bộ và không đồng bộ với chỉ try/catch.

Gần đây tôi đã viết bài đăng này cho thấy những ưu điểm của async / await so với các lời hứa trong một số trường hợp sử dụng phổ biến với các ví dụ về mã: 6 lý do tại sao JavaScript Async / Await Blows Promise Away (Hướng dẫn)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.