Không đồng bộ đang chờ trong điều kiện if JavaScript

Bạn đang sử dụng 
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?

  1. Đầ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
  2. 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ụ
  3. Javascript đăng xuất "Súp gì"?
  4. 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
  5. 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
  6. 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ố 8

Khô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"]
0

Do đó, 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ận

Nế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

Fredrik Strand Oseberg

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

Chủ Đề