process.on['unhandledRejection', [err] => {
console.error[err];
process.exit[1];
}]
1 trong quá trình sản xuất hay bạn định không bao giờ chạm vào nó? Chà, hóa ra để hiểu được các hàm không đồng bộ đòi hỏi rất nhiều kiến thức về cách thức hoạt động cơ bản của JavaScript
Hãy cùng khám phá khái niệm này và tìm hiểu nhiều điều về JavaScript trong quá trình này
Bạn đã sẵn sàng chưa?
Mã không đồng bộ là gì?
Theo thiết kế, JavaScript là ngôn ngữ lập trình đồng bộ. Điều này có nghĩa là khi mã được thực thi, JavaScript bắt đầu ở đầu tệp và chạy qua từng dòng mã cho đến khi hoàn thành
Kết quả của quyết định thiết kế này là chỉ có một điều có thể xảy ra tại một thời điểm
Bạn có thể nghĩ về điều này như thể bạn đang tung hứng sáu quả bóng nhỏ. Trong khi bạn đang tung hứng, tay của bạn đang bận và không thể xử lý bất cứ điều gì khác
Tương tự với JavaScript. một khi mã đang chạy, nó sẽ có đầy đủ mã đó. Chúng tôi gọi đây là loại chặn mã đồng bộ. Bởi vì nó chặn mã khác chạy một cách hiệu quả
Hãy quay lại ví dụ tung hứng. Điều gì sẽ xảy ra nếu bạn muốn thêm một quả bóng khác? . Đó có thể là một vấn đề
Bạn không muốn ngừng tung hứng, bởi vì nó rất thú vị. Nhưng bạn cũng không thể đi và lấy một quả bóng khác, bởi vì điều đó có nghĩa là bạn phải dừng lại
Giải pháp? . Họ không tung hứng, vì vậy họ có thể đi lấy bóng cho bạn, sau đó tung nó vào phần tung hứng của bạn vào thời điểm khi tay bạn rảnh và bạn đã sẵn sàng để thêm một quả bóng khác vào giữa màn tung hứng
Đây là mã không đồng bộ. JavaScript đang ủy thác công việc cho một thứ khác, sau đó tiếp tục công việc kinh doanh của chính nó. Sau đó, khi nó sẵn sàng, nó sẽ nhận lại kết quả từ công việc
Ai đang làm công việc kia?
Được rồi, vậy là chúng ta biết rằng JavaScript đồng bộ và lười biếng. Nó không muốn tự mình làm tất cả công việc, vì vậy nó chuyển nó sang thứ khác
Nhưng ai là thực thể bí ẩn làm việc cho JavaScript này?
Chà, hãy xem một ví dụ về mã không đồng bộ
const logName = [] => {
console.log["Han"]
}
setTimeout[logName, 0]
console.log["Hi there"]
Chạy mã này dẫn đến đầu ra sau trong bảng điều khiển
// in console
Hi there
Han
Ổn thỏa. Điều gì đang xảy ra?
Hóa ra cách chúng tôi tạo ra công việc trong JavaScript là sử dụng các hàm và API dành riêng cho môi trường. Và đây là một nguồn gây nhầm lẫn lớn trong JavaScript
JavaScript luôn chạy trong một môi trường
Thông thường, môi trường đó là trình duyệt. Nhưng nó cũng có thể ở trên máy chủ với NodeJS. Nhưng những gì trên trái đất là sự khác biệt?
Sự khác biệt - và điều này rất quan trọng - là trình duyệt và máy chủ [NodeJS], về mặt chức năng, không tương đương nhau. Chúng thường giống nhau, nhưng chúng không giống nhau
Hãy minh họa điều này với một ví dụ. Giả sử JavaScript là nhân vật chính của một cuốn sách giả tưởng hoành tráng. Chỉ là một đứa trẻ nhà nông bình thường
Bây giờ hãy nói rằng đứa trẻ nông dân này đã tìm thấy hai bộ áo giáp đặc biệt mang lại cho chúng sức mạnh vượt xa sức mạnh của chính chúng
Khi họ sử dụng bộ áo giáp trình duyệt, họ có quyền truy cập vào một số khả năng nhất định
Khi họ sử dụng bộ áo giáp của máy chủ, họ có quyền truy cập vào một bộ khả năng khác
Những bộ quần áo này có một số trùng lặp, bởi vì những người tạo ra những bộ quần áo này có cùng nhu cầu ở một số nơi, nhưng không phải ở những nơi khác
Đây là những gì một môi trường là. Nơi mã được chạy, nơi tồn tại các công cụ được xây dựng dựa trên ngôn ngữ JavaScript hiện có. Chúng không phải là một phần của ngôn ngữ, nhưng dòng này thường bị mờ vì chúng ta sử dụng các công cụ này hàng ngày khi viết mã
setTimeout, tìm nạp và DOM là tất cả các ví dụ về API Web. [Bạn có thể xem danh sách đầy đủ các Web API tại đây. ] Chúng là những công cụ được tích hợp trong trình duyệt và được cung cấp cho chúng tôi khi mã của chúng tôi được chạy
Và vì chúng tôi luôn chạy JavaScript trong một môi trường nên có vẻ như đây là một phần của ngôn ngữ. Nhưng họ không
Vì vậy, nếu bạn đã từng thắc mắc tại sao bạn có thể sử dụng tìm nạp trong JavaScript khi chạy nó trên trình duyệt [nhưng cần cài đặt gói khi bạn chạy nó trong NodeJS], thì đây là lý do tại sao. Ai đó nghĩ rằng tìm nạp là một ý tưởng hay và xây dựng nó như một công cụ cho môi trường NodeJS
Gây nhầm lẫn?
Nhưng bây giờ cuối cùng chúng ta cũng có thể hiểu JavaScript đảm nhận công việc gì và cách nó được tuyển dụng
Hóa ra chính môi trường đảm nhận công việc và cách để môi trường thực hiện công việc đó là sử dụng chức năng thuộc về môi trường. Ví dụ: tìm nạp hoặc setTimeout trong môi trường trình duyệt
Điều gì xảy ra với công việc?
Tuyệt quá. Vì vậy môi trường đảm nhận công việc. Rồi sao?
Tại một số điểm bạn cần lấy lại kết quả. Nhưng hãy nghĩ xem nó sẽ hoạt động như thế nào
Hãy quay lại ví dụ tung hứng từ đầu. Hãy tưởng tượng bạn yêu cầu một quả bóng mới và một người bạn bắt đầu ném quả bóng vào bạn khi bạn chưa sẵn sàng
Đó sẽ là một thảm họa. Có lẽ bạn có thể gặp may mắn và nắm bắt nó và đưa nó vào thói quen của bạn một cách hiệu quả. Nhưng có khả năng lớn là nó có thể khiến bạn đánh rơi tất cả các quả bóng của mình và làm hỏng thói quen của bạn. Sẽ không tốt hơn nếu bạn đưa ra những hướng dẫn nghiêm ngặt về thời điểm nhận bóng?
Hóa ra, có những quy tắc nghiêm ngặt xung quanh thời điểm JavaScript có thể nhận công việc được ủy quyền
Các quy tắc đó được điều chỉnh bởi vòng lặp sự kiện và liên quan đến hàng đợi vi tác vụ và tác vụ vĩ mô. Vâng tôi biết. nó rất nhiều. Nhưng chịu đựng với tôi
Ổn thỏa. Vì vậy, khi chúng tôi ủy quyền mã không đồng bộ cho trình duyệt, trình duyệt sẽ nhận và chạy mã và đảm nhận khối lượng công việc đó. Nhưng có thể có nhiều tác vụ được giao cho trình duyệt, vì vậy chúng tôi cần đảm bảo rằng chúng tôi có thể ưu tiên các tác vụ này
Đây là nơi hàng đợi vi tác vụ và hàng đợi tác vụ vĩ mô phát huy tác dụng. Trình duyệt sẽ nhận công việc, thực hiện nó, sau đó đặt kết quả vào một trong hai hàng đợi dựa trên loại công việc mà nó nhận được
Ví dụ: các lời hứa được đặt trong hàng đợi vi tác vụ và có mức độ ưu tiên cao hơn
Sự kiện và setTimeout là những ví dụ về công việc được đặt trong hàng đợi tác vụ vĩ mô và có mức độ ưu tiên thấp hơn
Bây giờ, khi công việc đã hoàn thành và được đặt vào một trong hai hàng đợi, vòng lặp sự kiện sẽ chạy đi chạy lại và kiểm tra xem JavaScript đã sẵn sàng nhận kết quả hay chưa
Chỉ khi JavaScript chạy xong tất cả mã đồng bộ của nó, tốt và sẵn sàng, vòng lặp sự kiện mới bắt đầu chọn từ hàng đợi và chuyển các chức năng trở lại JavaScript để chạy
Vì vậy, hãy xem một ví dụ
setTimeout[[] => console.log["hello"], 0]
fetch["//someapi/data"].then[response => response.json[]]
.then[data => console.log[data]]
console.log["What soup?"]
Thứ tự sẽ là gì đây?
- Đầu tiên, setTimeout được ủy quyền cho trình duyệt, trình duyệt này thực hiện công việc và đặt hàm kết quả vào hàng đợi macrotask
- Lần tìm nạp thứ hai được ủy quyền cho trình duyệt, trình duyệt này sẽ thực hiện công việc. Nó lấy dữ liệu từ điểm cuối và đặt các hàm kết quả vào hàng đợi vi tác vụ
- Javascript đăng xuất "Súp gì"?
- Vòng lặp sự kiện kiểm tra xem JavaScript đã sẵn sàng nhận kết quả từ công việc được xếp hàng đợi hay chưa
- Khi bảng điều khiển. nhật ký đã hoàn tất, JavaScript đã sẵn sàng. Vòng lặp sự kiện chọn các chức năng được xếp hàng đợi từ hàng đợi vi tác vụ, có mức độ ưu tiên cao hơn và đưa chúng trở lại JavaScript để thực thi
- Sau khi hàng đợi vi tác vụ trống, lệnh gọi lại setTimeout được đưa ra khỏi hàng đợi tác vụ lớn và được trả lại cho JavaScript để thực thi
In console:
// What soup?
// the data from the api
// hello
lời hứa
Bây giờ bạn đã có nhiều kiến thức về cách mã không đồng bộ được xử lý bởi JavaScript và môi trường trình duyệt. Vì vậy, hãy nói về những lời hứa
Lời hứa là một cấu trúc JavaScript đại diện cho một giá trị không xác định trong tương lai. Về mặt khái niệm, một lời hứa chỉ là JavaScript hứa trả về một giá trị. Đó có thể là kết quả của lệnh gọi API hoặc có thể là đối tượng lỗi do yêu cầu mạng không thành công. Bạn được đảm bảo để có được một cái gì đó
const promise = new Promise[[resolve, reject] => {
// Make a network request
if [response.status === 200] {
resolve[response.body]
} else {
const error = { .. }
reject[error]
}
}]
promise.then[res => {
console.log[res]
}].catch[err => {
console.log[err]
}]
Một lời hứa có thể có các trạng thái sau
- hoàn thành - hành động hoàn thành thành công
- bị từ chối - hành động không thành công
- đang chờ xử lý - chưa có hành động nào được hoàn thành
- giải quyết - đã được thực hiện hoặc bị từ chối
Một lời hứa nhận được một chức năng giải quyết và từ chối có thể được gọi để kích hoạt một trong những trạng thái này
Một trong những điểm bán hàng lớn của lời hứa là chúng ta có thể xâu chuỗi các chức năng mà chúng ta muốn xảy ra khi thành công [giải quyết] hoặc thất bại [từ chối]
- Để đăng ký một chức năng để chạy thành công, chúng tôi sử dụng. sau đó
- Để đăng ký một chức năng để chạy khi thất bại, chúng tôi sử dụng. nắm lấy
// Fetch returns a promise
fetch["//swapi.dev/api/people/1"]
.then[[res] => console.log["This function is run when the request succeeds", res]
.catch[err => console.log["This function is run when the request fails", err]
// Chaining multiple functions
fetch["//swapi.dev/api/people/1"]
.then[[res] => doSomethingWithResult[res]]
.then[[finalResult] => console.log[finalResult]]
.catch[[err => doSomethingWithErr[err]]
Hoàn hảo. Bây giờ chúng ta hãy xem xét kỹ hơn điều này trông như thế nào dưới mui xe, sử dụng tìm nạp làm ví dụ
const fetch = [url, options] => {
// simplified
return new Promise[[resolve, reject] => {
const xhr = new XMLHttpRequest[]
// .. make request
xhr.onload = [] => {
const options = {
status: xhr.status,
statusText: xhr.statusText
...
}
resolve[new Response[xhr.response, options]]
}
xhr.onerror = [] => {
reject[new TypeError["Request failed"]]
}
}
fetch["//swapi.dev/api/people/1"]
// Register handleResponse to run when promise resolves
.then[handleResponse]
.catch[handleError]
// conceptually, the promise looks like this now:
// { status: "pending", onsuccess: [handleResponse], onfailure: [handleError] }
const handleResponse = [response] => {
// handleResponse will automatically receive the response, ¨
// because the promise resolves with a value and automatically injects into the function
console.log[response]
}
const handleError = [response] => {
// handleError will automatically receive the error, ¨
// because the promise resolves with a value and automatically injects into the function
console.log[response]
}
// the promise will either resolve or reject causing it to run all of the registered functions in the respective arrays
// injecting the value. Let's inspect the happy path:
// 1. XHR event listener fires
// 2. If the request was successfull, the onload event listener triggers
// 3. The onload fires the resolve[VALUE] function with given value
// 4. Resolve triggers and schedules the functions registered with .then
Vì vậy, chúng tôi có thể sử dụng các lời hứa để thực hiện công việc không đồng bộ và để đảm bảo rằng chúng tôi có thể xử lý bất kỳ kết quả nào từ những lời hứa đó. Đó là đề xuất giá trị. Nếu bạn muốn biết thêm về những lời hứa, bạn có thể đọc thêm về chúng tại đây và tại đây
Khi chúng tôi sử dụng lời hứa, chúng tôi xâu chuỗi các chức năng của mình vào lời hứa để xử lý các tình huống khác nhau
Điều này hoạt động, nhưng chúng tôi vẫn cần xử lý logic bên trong các cuộc gọi lại [các hàm lồng nhau] sau khi chúng tôi nhận lại kết quả của mình. Điều gì sẽ xảy ra nếu chúng ta có thể sử dụng lời hứa nhưng viết mã tìm kiếm đồng bộ?
Không đồng bộ/Đang chờ
Async/Await là một cách viết lời hứa cho phép chúng ta viết mã không đồng bộ theo cách đồng bộ. Chúng ta hãy có một cái nhìn
________số 8Không có gì thay đổi dưới mui xe ở đây. Chúng tôi vẫn đang sử dụng các lời hứa để tìm nạp dữ liệu, nhưng bây giờ nó có vẻ đồng bộ và chúng tôi không còn. sau đó và. bắt khối
Async/Await thực chất chỉ là cú pháp cung cấp một cách để tạo mã dễ suy luận hơn mà không thay đổi động lực cơ bản
Chúng ta hãy xem nó hoạt động như thế nào
Async/Await cho phép chúng tôi sử dụng trình tạo để tạm dừng thực thi chức năng. Khi chúng tôi đang sử dụng async/await, chúng tôi không chặn vì chức năng này đang mang lại quyền kiểm soát cho chương trình chính
Sau đó, khi lời hứa được giải quyết, chúng tôi đang sử dụng trình tạo để mang lại quyền kiểm soát cho hàm không đồng bộ với giá trị từ lời hứa đã giải quyết
Bạn có thể đọc thêm tại đây để có cái nhìn tổng quan về bộ tạo và mã không đồng bộ
Trên thực tế, bây giờ chúng ta có thể viết mã không đồng bộ trông giống như mã đồng bộ. Điều đó có nghĩa là dễ suy luận hơn và chúng ta có thể sử dụng các công cụ đồng bộ để xử lý lỗi như thử / bắt
const getData = async [] => {
try {
const response = await fetch["//jsonplaceholder.typicode.com/todos/1"]
const data = await response.json[]
console.log[data]
} catch [err] {
console.log[err]
}
}
getData[]
Ổn thỏa. Vì vậy, làm thế nào để chúng ta sử dụng nó? . Điều này không làm cho nó trở thành một chức năng không đồng bộ, nó chỉ cho phép chúng ta sử dụng sự chờ đợi bên trong nó
Không cung cấp từ khóa async sẽ dẫn đến lỗi cú pháp khi cố gắng sử dụng await bên trong một chức năng thông thường
const logName = [] => {
console.log["Han"]
}
setTimeout[logName, 0]
console.log["Hi there"]
0Do đó, chúng tôi không thể sử dụng async/await trên mã cấp cao nhất. Nhưng không đồng bộ và chờ đợi vẫn chỉ là cú pháp thay vì lời hứa. Vì vậy, chúng tôi có thể xử lý các trường hợp cấp cao nhất với chuỗi lời hứa
// in console
Hi there
Han
0Điều này cho thấy một sự thật thú vị khác về async/await. Khi xác định một chức năng là không đồng bộ, nó sẽ luôn trả về một lời hứa
Sử dụng async/await lúc đầu có vẻ giống như phép thuật. Nhưng giống như bất kỳ phép thuật nào, đó chỉ là công nghệ đủ tiên tiến đã phát triển qua nhiều năm. Hy vọng rằng bây giờ bạn đã nắm vững các nguyên tắc cơ bản và có thể tự tin sử dụng async/await
Phần kết luậnNếu bạn đã làm nó ở đây, xin chúc mừng. Bạn vừa thêm một phần kiến thức quan trọng về JavaScript và cách nó hoạt động với các môi trường của nó vào hộp công cụ của bạn
Đây chắc chắn là một chủ đề khó hiểu và các dòng không phải lúc nào cũng rõ ràng. Nhưng bây giờ, hy vọng bạn đã nắm được cách JavaScript hoạt động với mã không đồng bộ trong trình duyệt và hiểu rõ hơn về cả promise và async/await
Nếu bạn thích bài viết này, bạn cũng có thể thích kênh youtube của tôi. Tôi hiện đang có một loạt bài về kiến thức cơ bản về web về HTTP, xây dựng máy chủ web từ đầu và hơn thế nữa
Ngoài ra còn có một loạt bài về xây dựng toàn bộ ứng dụng bằng React, nếu đó là vấn đề của bạn. Và tôi dự định sẽ thêm nhiều nội dung hơn nữa ở đây trong tương lai sẽ đi sâu vào các chủ đề JavaScript
Và nếu bạn muốn nói xin chào hoặc trò chuyện về phát triển web, bạn luôn có thể liên hệ với tôi trên twitter tại @foseberg. Cảm ơn vì đã đọc
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
QUẢNG CÁO
Tôi là một cựu doanh nhân tự học đã trở thành nhà tư vấn phát triển web. Có kiến thức về Javascript và Golang
Nếu bạn đọc đến đây, hãy tweet cho tác giả để cho họ thấy bạn quan tâm. Tweet một lời cảm ơn
Học cách viết mã miễn phí. Chương trình giảng dạy mã nguồn mở của freeCodeCamp đã giúp hơn 40.000 người có được việc làm với tư cách là nhà phát triển. Bắt đầu