Hướng dẫn can you make javascript synchronous? - bạn có thể tạo javascript đồng bộ không?

Giới thiệu

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à 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.

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.

Bắt đầu nào

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:

Yêu cầu ví dụ sử dụng lời hứa

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 async/await:

Yêu cầu ví dụ sử dụng async/chờ đợi

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 .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.

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.

Chức năng không đồng bộ

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 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.

Ví dụ đơn giản sử dụng async/chờ đợi

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, try/catch hoạt động kỳ diệu một lần nữa.

Ví dụ đơn giản sử dụng async/đang chờ thử/bắt

Đ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ề 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/await4 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/await5 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/await6 trong mã sẵn sàng sản xuất của bạn (phải không?).

Ví dụ xấu về lỗi đang được xử lý bằng cách sử dụng lời hứa

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/await8.

Ví dụ về lỗi đang được xử lý bằng cách sử dụng async/chờ đợi

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/catches, í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ứa

Chỉ 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.

Ví dụ có điều kiện sử dụng async/chờ đợi

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:

Ví dụ vòng lặp bằng cách sử dụng .then2

Ví 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ứa

Tuy 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 .then3 thông thường.

Ví dụ sử dụng async/chờ đợi và cho .. của vòng lặp

Ồ, nhưng lưu ý rằng bạn không thể sử dụng bất kỳ vòng lặp .then4 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 .then6 như .then7, .then4, 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.

Ví dụ sử dụng foreach với async/chờ đợi

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?

Ví dụ thứ hai sử dụng foreach với async/chờ đợi

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 response0 đượ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 .then4Returns. Kết quả là, bạn có thể await kết thúc response3.

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ó response5. 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.

Ví dụ hiển thị sự đồng tình với những lời hứa

Sử dụng response6, 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 response7.

Ví dụ hiển thị sự đồng tình với async/chờ đợi

Đơ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ờ đợi

Như 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 response8 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 (response9). Cuối cùng, chúng tôi gán kết quả cho các biến tương ứng async0, async1 và async2. 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 response5 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ộ async4 và async5.

Ví dụ kiểm tra đơn vị với lời hứa

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 async6 và async7 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ờ).

Ví dụ kiểm tra đơn vị thứ hai với lời hứa

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ờ đợi

Khá đơ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 ứng async9 với giá trị đó. b) Trả lại một lời hứa có nghĩa là async9 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/catches, í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ức await6.
  • 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! :)

JavaScript có thể đồng bộ không?

JavaScript là spoiler đồng bộ: Tại cơ sở của nó, JavaScript là một ngôn ngữ đồng bộ, chặn, đơn luồng.Điều đó chỉ có nghĩa là chỉ có một hoạt động có thể được tiến hành tại một thời điểm.Đó không phải là toàn bộ câu chuyện, mặc dù! Spoiler: at its base, JavaScript is a synchronous, blocking, single-threaded language. That just means that only one operation can be in progress at a time. That's not the entire story, though!

Là JavaScript thực sự không đồng bộ?

JavaScript là một ngôn ngữ lập trình đồng thời, không chặn, không đồng bộ, không đồng thời với rất nhiều sự linh hoạt. with lots of flexibility.

JS có đồng bộ theo mặc định không?

JavaScript đồng bộ theo mặc định và là một luồng.Điều này có nghĩa là mã không thể tạo các luồng mới và chạy song song. and is single threaded. This means that code cannot create new threads and run in parallel.

Là JavaScript đồng bộ hay không đồng bộ bởi bản chất?

JavaScript là một ngôn ngữ lập trình không đồng bộ và đồng thời mang lại nhiều sự linh hoạt nhưng cũng đồng thời là một luồng đơn và không chặn.Mặc dù bản chất nó đồng bộ, JavaScript có thể được hưởng lợi từ mã không đồng bộ.synchronous by nature, JavaScript can benefit from asynchronous code.