Kể từ khi phát hành ECMAScript 2017 [ES8] và việc áp dụng hỗ trợ theo mặc định trên Node.js 7.6, bạn không còn lý do nào vì không sử dụng một trong các tính năng ES8 nóng nhất, đó là Nhưng trước hết, vì những lời hứa là nền tảng của các chức năng ASYNC, để có thể nắm bắt nội dung của bài viết này, bạn sẽ cần một kiến thức đáng tin cậy về những lời hứa và ít nhất là nhận thức về máy phát điện. Trong bài viết này, chúng tôi đã giành được độ sâu trong cả hai tính năng sử dụng và chức năng, nhưng để thực sự hiểu cách thức hoạt động của nó, tôi thực sự khuyên bạn nên sử dụng loạt ponyfoo này, bao gồm hoàn toàn mọi thứ bạn phải biết về lời hứa, máy phát điện, v.v. Lời hứa đã hạ cánh trên JavaScript như là một phần của tiêu chuẩn ECMAScript 2015 [ES6] và tại thời điểm phát hành, nó đã thay đổi cách các nhà phát triển sử dụng để viết mã không đồng bộ. Một trong những thành tựu hứa hẹn quan trọng nhất là nó làm giảm đáng kể sự phức tạp của mã không đồng bộ, cải thiện mức độ dễ đọc, bên cạnh việc giúp chúng ta thoát khỏi Kim tự tháp Doom [còn được gọi là địa ngục gọi lại]. Bằng cách sử dụng lời hứa, một yêu cầu đơn giản cho API GitHub trông như thế này: OK, tôi phải thừa nhận rằng nó khá rõ ràng và chắc chắn làm cho sự hiểu biết dễ tiếp cận hơn so với khi sử dụng các cuộc gọi lại lồng nhau, nhưng nếu tôi nói với bạn rằng chúng ta có thể viết mã không đồng bộ như thế này, bằng cách sử dụng Nó chỉ đơn giản là khả năng đọc ở đầu của nó. Bạn có thể xác định từng bước của quy trình một cách rõ ràng, giống như nếu bạn đã đọc một mã đồng bộ, nhưng nó hoàn toàn không đồng bộ! Ngay cả trong ví dụ giả định ở trên, nó cũng rõ ràng, chúng tôi đã lưu một lượng mã kha khá. Chúng tôi đã phải viết Những lợi thế nhỏ cộng lại nhanh chóng, điều này sẽ trở nên rõ ràng hơn trong các ví dụ mã sau. Vì vậy, hãy để Lừa nhảy vào thực hiện các chức năng Async. Bất kỳ hàm async nào trả về một lời hứa ngầm và giá trị được giải quyết của lời hứa sẽ là bất cứ lợi nhuận nào từ chức năng của bạn. Hàm của chúng tôi có từ khóa Nếu lời hứa giải quyết, chúng ta có thể tương tác ngay lập tức với nó trên dòng tiếp theo. Và nếu nó từ chối, thì một lỗi được ném. Vì vậy, Điều đó cho phép chúng tôi viết mã trông đồng bộ ngay từ cái nhìn đầu tiên nhưng không đồng bộ dưới mui xe, và đó là phần tốt nhất về Giới thiệu
async/await
. Mục đích của bài viết này là cho bạn thấy một loạt các lý do với các ví dụ về lý do tại sao bạn nên áp dụng nó ngay lập tức và không bao giờ nhìn lại.Bắt đầu nào
async/await
:.then
, tạo một hàm ẩn danh để xử lý phản hồi hoặc đặt tên response
cho một biến mà chúng tôi không cần sử dụng - và chúng tôi cũng tránh được mã lồng nhau.Chức năng không đồng bộ
async
theo định nghĩa của nó [tất nhiên nói rằng chức năng này sẽ là một hàm async]. Nó cũng có một từ khóa await
mà chúng tôi sử dụng để chờ đợi một lời hứa. Điều này cũng ngụ ý rằng chúng ta chỉ có thể sử dụng các hàm await
Inside được xác định với từ khóa async
.try/catch
hoạt động kỳ diệu một lần nữa.async/await
. Đó là nơi mà tất cả sức mạnh của nó nằm. Thực tế là API trả về một lời hứa thay vì chặn vòng lặp sự kiện chỉ là một chi tiết triển khai. Và vì Node.js 8 có chức năng tiện ích mới chuyển đổi chức năng dựa trên cuộc gọi lại thành một chức năng dựa trên lời hứa, được gọi là ____10, chúng tôi được đề cập khá nhiều khi sử dụng các hàm ASYNC thậm chí hoạt động với mã Legacy Legacy.
Chịu trách nhiệm [xử lý lỗi]
Có một vài vấn đề mà tôi đã gặp phải khi chơi với điều này, vì vậy, thật tốt khi nhận thức được chúng.
Với sức mạnh to lớn có trách nhiệm lớn - Benjamin Parker
Một trong những vấn đề ngấm ngầm nhất khi làm việc với các chức năng Async là bạn phải cẩn thận vì các lỗi bị nuốt một cách âm thầm [!!] trong một hàm ASYNC - giống như bên trong những lời hứa tiêu chuẩn. Trừ khi chúng tôi thêm một try/catch
, các khối xung quanh các biểu thức đang chờ đợi của chúng tôi, các trường hợp ngoại lệ chưa được thực hiện - bất kể chúng có được nuôi dưỡng trong cơ thể của chức năng async của bạn hay trong khi nó bị đình chỉ trong await
, sẽ từ chối lời hứa được trả lại bởi hàm async.
Trong ví dụ dưới đây mà chúng tôi sử dụng lời hứa, try/catch
đã giành được xử lý nếu async/await
4 thất bại vì nó xảy ra trong một lời hứa. Chúng tôi cần gọi async/await
5 theo lời hứa và sao chép mã xử lý lỗi của chúng tôi, điều này sẽ [hy vọng] tinh vi và thanh lịch hơn so với async/await
6 trong mã sẵn sàng sản xuất của bạn [phải không?].
Bây giờ hãy xem cùng một mã, nhưng lần này sử dụng async/await
. Khối bắt bây giờ sẽ xử lý mọi lỗi phân tích cú pháp async/await
8.
Lời khuyên của tôi là đảm bảo rằng các chức năng async
của bạn hoàn toàn được bao quanh bởi try/catch
es, ít nhất là ở cấp cao nhất.
Đối phó với các điều kiện
Hãy xem xét một khối mã như mã bên dưới tìm nạp một số dữ liệu và quyết định xem nó sẽ trả về hoặc nhận thêm chi tiết dựa trên một số giá trị trong dữ liệu.
Ví dụ có điều kiện sử dụng lời hứaChỉ cần nhìn vào điều này cho bạn ớn lạnh. Nó dễ dàng bị lạc trong tất cả các tổ [6 cấp], niềng răng và các tuyên bố trở lại chỉ cần thiết để tuyên truyền kết quả cuối cùng cho đến lời hứa chính.
Ví dụ này trở nên dễ hiểu hơn khi viết lại với async/await
.
Khá gọn gàng, hả? Chúng tôi đã giảm mức thụt ở hai cấp độ và biến nó thành dễ đọc hơn nhiều, đặc biệt là bằng cách sử dụng lợi nhuận sớm.
Vòng lặp
Các chức năng Async trở nên thực sự ấn tượng khi nói đến sự lặp lại. Chẳng hạn, hãy để nói rằng chúng tôi muốn chèn một số bài đăng vào cơ sở dữ liệu của chúng tôi, nhưng theo tuần tự. Đó là, chúng tôi muốn những lời hứa thực hiện lần lượt, không đồng thời. Bằng cách sử dụng lời hứa, chúng tôi phải thực hiện chuỗi hứa hẹn của mình. Hãy xem xét ví dụ dưới đây minh họa rằng:
.then
2Ví dụ trên hoạt động, nhưng chắc chắn là khó coi. Nó cũng dễ bị lỗi, bởi vì nếu bạn vô tình làm một cái gì đó như khối mã bên dưới, thì lời hứa sẽ thực hiện đồng thời, điều này có thể dẫn đến kết quả bất ngờ.
Ví dụ thứ hai sử dụng foreach và lời hứaTuy nhiên, sử dụng các chức năng Async, chúng ta chỉ có thể sử dụng vòng lặp .then
3 thông thường.
Ồ, nhưng lưu ý rằng bạn không thể sử dụng bất kỳ vòng lặp .then
4 nào ở đây. Tại sao? Chà, đó là đơn giản. Điều đó xảy ra bởi vì await
chỉ ảnh hưởng đến hàm async trong cùng bao quanh nó và chỉ có thể được sử dụng trực tiếp bên trong các hàm async. Đó là một vấn đề nếu bạn muốn sử dụng một trong các chức năng tiện ích .then
6 như .then
7, .then
4, v.v., vì chúng dựa vào các cuộc gọi lại. Khối mã dưới đây sẽ thất bại do những lý do này.
Nhưng có lẽ bạn nghĩ rằng một cái gì đó như thế này có thể hoạt động, sau tất cả, có một từ khóa async
tiền tố chức năng gọi lại, phải không?
Không may măn. Một lần nữa, mã này không hoạt động, nhưng có một cảnh báo: lời hứa được trả lại bởi response
0 được giải quyết không đồng bộ, điều đó có nghĩa là các cuộc gọi lại đã giành được kết thúc khi .then
4Returns. Kết quả là, bạn có thể await
kết thúc response
3.
Tiếp tục: Toàn bộ ý tưởng ở đây là không await
trong các cuộc gọi lại.
Tuần tự so với song song
Điều quan trọng cần lưu ý là, ngay cả khi sử dụng các hàm Async và mã của bạn không đồng bộ, nó sẽ được thực thi theo cách nối tiếp, điều đó có nghĩa là một câu lệnh [ngay cả những câu không đồng bộ] sẽ thực hiện từng câu này. Nhưng vì các chức năng ASYNC trở thành lời hứa, chúng ta có thể sử dụng một quy trình công việc để chúng ta sử dụng cho những lời hứa để xử lý sự song song.
Hãy nhớ rằng với những lời hứa chúng ta có response
5. Hãy để sử dụng nó để trả về một loạt các giá trị từ một loạt các lời hứa.
Sử dụng response
6, chúng ta có thể làm điều này theo cách đơn giản hơn bằng cách sử dụng cùng một response
7.
Đơn giản như thế. Lưu ý rằng các phần quan trọng nhất là, trước tiên, tạo ra mảng lời hứa, bắt đầu gọi tất cả các lời hứa ngay lập tức. Thứ hai, chúng tôi đang chờ đợi những lời hứa trong chức năng chính. Hãy xem xét khối mã bên dưới, minh họa ba lời hứa khác nhau sẽ thực hiện song song.
Ví dụ thứ hai cho thấy sự đồng tình với async/chờ đợiNhư ví dụ đầu tiên, đầu tiên chúng tôi tạo ra một loạt các lời hứa [mỗi một trong số các hàm response
8 là một lời hứa]. Sau đó, chúng tôi thực hiện tất cả chúng đồng thời và đồng thời, chờ đợi tất cả chúng kết thúc [response
9]. Cuối cùng, chúng tôi gán kết quả cho các biến tương ứng async
0, async
1 và async
2. Mặc dù thực tế là nó hoạt động, nhưng điều quan trọng là phải nói rằng sử dụng response
5 cho mọi thứ là một ý tưởng tồi.
Để hiểu rõ hơn về cách thức hoạt động, bạn phải nhận thức được rằng nếu một trong những lời hứa thất bại, tất cả chúng sẽ bị hủy bỏ, điều gì sẽ dẫn đến - trong ví dụ trước của chúng tôi - không ai trong ba biến này nhận được giá trị dự kiến.
Kiểm tra đơn vị với các chức năng Async
Bằng cách sử dụng các chức năng Async, bạn thậm chí có thể áp dụng các thử nghiệm đơn vị cho các chức năng của mình. Mã sau đây sử dụng mocha tự động tác để kiểm tra đơn vị các hàm không đồng bộ async
4 và async
5.
Thử nghiệm này luôn thành công, bởi vì Mocha không đợi cho đến khi các xác nhận trong dòng async
6 và async
7 thực thi. Bạn có thể sửa chữa điều này bằng cách trả về kết quả của chuỗi hứa hẹn, bởi vì Mocha nhận ra nếu một bài kiểm tra trả lại lời hứa và sau đó chờ cho đến khi lời hứa đó được giải quyết [trừ khi có thời gian chờ].
Thuận tiện, các chức năng Async luôn trả lại lời hứa, điều này làm cho chúng hoàn hảo cho loại bài kiểm tra đơn vị này.
Ví dụ kiểm tra đơn vị với async/chờ đợiKhá đơn giản, hả? Do đó, có hai lợi thế khi sử dụng các hàm ASYNC cho các thử nghiệm đơn vị không đồng bộ trong Mocha: Mã này sẽ ngắn gọn hơn và những lời hứa trở lại cũng được thực hiện.
Lời khuyên nhanh chóng và phải nhớ
- Các chức năng không đồng bộ được bắt đầu đồng bộ, giải quyết không đồng bộ.
- Trên các chức năng
async/await
, những lời hứa được trả lại không được gói gọn. Điều đó có nghĩa là a] Trả lại giá trị không dự đoán đáp ứngasync
9 với giá trị đó. b] Trả lại một lời hứa có nghĩa làasync
9 hiện phản ánh trạng thái của lời hứa đó. - Bạn có thể chuyển tiếp cả sự hoàn thành và từ chối tính toán không đồng bộ khác mà không cần chờ đợi. Điều đó có nghĩa là bạn trả về các giá trị có thể được xử lý bởi một hàm
async
khác. - Bạn không cần
await
nếu bạn lửa và quên đi. Đôi khi bạn chỉ muốn kích hoạt tính toán không đồng bộ và không quan tâm đến khi nó kết thúc. - Bạn có thể
await
trên các cuộc gọi lại, vì nó có thể mang lại cho bạn rất nhiều lỗi. - Các chức năng không đồng bộ của bạn phải được bao quanh hoàn toàn bởi
try/catch
es, ít nhất là ở cấp cao nhất. - Đối với chủ nghĩa song song, bạn có thể đặt các hàm
async
của mình thành phương thứcawait
6. - Bạn có thể thực hiện thử nghiệm đơn vị với các chức năng
async
bằng cách sử dụng mocha tự nhận xét nghiệm. - Đôi khi bạn chỉ cần không cần phải lo lắng về những từ chối không được xử lý [hãy cẩn thận với điều này].
Sử dụng async/await
ngày hôm nay
Như đã chỉ vào đầu bài viết này, Node.js 7.6 đã được phát hành vài tháng trước [và Node.js 8, là phiên bản chính, đã được phát hành chỉ vài tuần trước], mang lại cho chúng tôi sự hỗ trợ và bảo hiểm mặc định cho async/await
. Điều đó có nghĩa là tính năng này không còn được coi là thử nghiệm và chúng tôi không cần sử dụng các trình biên dịch như Babel hoặc cờ await
0, là các tính năng gần như hoàn thành không được coi là ổn định bởi nhóm V8. Vì vậy, tất cả những gì bạn chỉ cần làm là cài đặt Node.js 8 và tận hưởng tất cả sức mạnh mà async/await
mang lại cho chúng tôi.
Sự kết luận
Các chức năng ASYNC là một khái niệm trao quyền được hỗ trợ đầy đủ và có sẵn trong ES8. Họ trả lại cho chúng tôi các await
2 đã mất của chúng tôi và ____ ____ 63/________ 64es, và họ thưởng cho kiến thức mà chúng tôi đã có được khi viết mã đồng bộ với các thành ngữ mới trông rất giống những người cũ, nhưng có hiệu suất hơn nhiều.
Và điều tốt là ngay cả Node.js 8 vẫn không phải là bản phát hành LTS [hiện tại nó trên V6.11.0], việc di chuyển cơ sở mã của bạn sang phiên bản mới rất có thể sẽ không cần nỗ lực.
Đặc biệt cảm ơn tất cả những người đã giúp tôi xem lại bản nháp của bài viết này. Bạn thật tuyệt vời! :]