Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ

Hãy để tôi bắt đầu bài viết này bằng cách hỏi, "JavaScript là gì"? Chà, đây là câu trả lời khó hiểu nhất mà tôi đã tìm thấy cho đến nay:

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.

Giữ một giây-nó có nói rằng một luồng đơn và không đồng bộ cùng một lúc không? Nếu bạn hiểu ý nghĩa của một luồng đơn, bạn có thể chủ yếu liên kết nó với các hoạt động đồng bộ. Làm thế nào mà JavaScript có thể không đồng bộ, sau đó?

Trong bài viết này, chúng tôi sẽ tìm hiểu tất cả về các phần đồng bộ và không đồng bộ của JavaScript. Bạn sử dụng cả hai trong chương trình web gần như hàng ngày.

Nếu bạn cũng thích học từ nội dung video, bài viết này cũng có sẵn dưới dạng hướng dẫn video ở đây: 🙂

Trong bài viết này, bạn sẽ học:

  • Làm thế nào JavaScript là đồng bộ.
  • Làm thế nào các hoạt động không đồng bộ xảy ra khi JavaScript được đọc đơn.
  • Làm thế nào hiểu được sự đồng bộ so với không đồng bộ giúp bạn hiểu rõ hơn về những lời hứa của JavaScript.
  • Rất nhiều ví dụ đơn giản nhưng mạnh mẽ để bao gồm các khái niệm này một cách chi tiết.

Chức năng JavaScript là công dân hạng nhất

Trong JavaScript, bạn có thể tạo và sửa đổi một hàm, sử dụng nó làm đối số, trả lại từ một hàm khác và gán nó cho một biến. Tất cả các khả năng này cho phép chúng tôi sử dụng các chức năng ở khắp mọi nơi để đặt một loạt các mã một cách hợp lý.

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ
Các dòng mã được tổ chức thành các chức năng một cách hợp lý

Chúng ta cần nói với công cụ JavaScript để thực hiện các chức năng bằng cách gọi chúng. Nó sẽ trông như thế này:

// Define a function
function f1() {
    // Do something
    // Do something again
    // Again
    // So on...
}

// Invoke the function
f1();

Theo mặc định, mọi dòng trong một hàm thực thi tuần tự, một dòng tại một thời điểm. Điều tương tự cũng được áp dụng ngay cả khi bạn gọi nhiều chức năng trong mã của mình. Một lần nữa, từng dòng.

JavaScript đồng bộ - Cách thức hoạt động của Chức năng thực thi chức năng

Vậy điều gì xảy ra khi bạn xác định một hàm và sau đó gọi nó? Công cụ JavaScript duy trì cấu trúc dữ liệu

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
5 được gọi là
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
6. Mục đích của ngăn xếp là để theo dõi chức năng hiện tại trong thực thi. Nó làm như sau:

  • Khi động cơ JavaScript gọi một hàm, nó sẽ thêm nó vào ngăn xếp và việc thực hiện bắt đầu.
  • Nếu chức năng hiện được thực thi gọi một hàm khác, động cơ sẽ thêm hàm thứ hai vào ngăn xếp và bắt đầu thực thi nó.
  • Khi nó hoàn thành thực thi chức năng thứ hai, động cơ sẽ lấy nó ra khỏi ngăn xếp.
  • Điều khiển quay trở lại để tiếp tục thực hiện hàm đầu tiên từ điểm nó để lại lần trước.
  • Khi việc thực hiện hàm đầu tiên kết thúc, động cơ sẽ đưa nó ra khỏi ngăn xếp.
  • Tiếp tục cùng một cách cho đến khi không có gì để đưa vào ngăn xếp.

Ngăn xếp thực thi chức năng còn được gọi là

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
7.

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ
Chức năng thực hiện ngăn xếp

Chúng ta hãy xem một ví dụ về ba chức năng thực thi từng cái một:

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();

Bây giờ chúng ta hãy xem điều gì xảy ra với ngăn xếp thực thi chức năng:

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ
Một luồng từng bước cho thấy thứ tự thực hiện

Bạn có thấy những gì đã xảy ra ở đó không? Đầu tiên,

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8 đi vào ngăn xếp, thực thi và bật ra. Sau đó,
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 cũng làm như vậy, và cuối cùng là
function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0. Sau đó, ngăn xếp trống, không có gì khác để thực hiện.

Ok, bây giờ chúng ta hãy làm việc thông qua một ví dụ phức tạp hơn. Dưới đây là một hàm

function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0 gọi một hàm khác
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 đến lượt nó gọi một hàm khác
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8.

function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();

Hãy xem những gì đang xảy ra với ngăn xếp thực thi chức năng:

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ
Một luồng từng bước cho thấy thứ tự thực hiện

Bạn có thấy những gì đã xảy ra ở đó không? Đầu tiên,

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8 đi vào ngăn xếp, thực thi và bật ra. Sau đó,
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 cũng làm như vậy, và cuối cùng là
function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0. Sau đó, ngăn xếp trống, không có gì khác để thực hiện.

Ok, bây giờ chúng ta hãy làm việc thông qua một ví dụ phức tạp hơn. Dưới đây là một hàm

function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0 gọi một hàm khác
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 đến lượt nó gọi một hàm khác
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8.

Hãy xem những gì đang xảy ra với ngăn xếp thực thi chức năng:

Lưu ý rằng

function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0 đầu tiên vào ngăn xếp, gọi một chức năng khác,
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9. Vì vậy, bây giờ
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 vào bên trong trong khi
function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0 vẫn còn trong ngăn xếp. Hàm
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 gọi
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8. Vì vậy, thời gian để
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8 đi vào bên trong ngăn xếp với cả
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9 và
function f1() {
  // Some code
}
function f2() {
  f1();
}
function f3() {
  f2();
}
f3();
0 còn lại bên trong.

Đầu tiên, function f1() { // some code } function f2() { // some code } function f3() { // some code } // Invoke the functions one by one f1(); f2(); f3();8 kết thúc thực hiện và ra khỏi ngăn xếp. Ngay sau đó function f1() { // some code } function f2() { // some code } function f3() { // some code } // Invoke the functions one by one f1(); f2(); f3();9 kết thúc, và cuối cùng là function f1() { // Some code } function f2() { f1(); } function f3() { f2(); } f3();0.

Điểm mấu chốt là tất cả mọi thứ xảy ra bên trong

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
6 là tuần tự. Đây là phần
function printMe() {
  console.log('print me');
}

setTimeout(printMe, 2000);
7 của JavaScript. Chủ đề
function printMe() {
  console.log('print me');
}

setTimeout(printMe, 2000);
8 của JavaScript đảm bảo rằng nó sẽ chăm sóc mọi thứ trong ngăn xếp trước khi nó bắt đầu nhìn vào bất cứ điều gì
function printMe() {
  console.log('print me');
}

setTimeout(printMe, 2000);
9.not occurring at the same time. What does it mean in the context of JavaScript?

Tuyệt quá! Bây giờ chúng tôi đã hiểu cách thức hoạt động

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
0 hoạt động trong JavaScript, bây giờ chúng ta hãy lật đồng xu và xem phía
function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
1 của nó. Bạn đã sẵn sàng chưa?

Trong những trường hợp này, bạn có thể không muốn công cụ JavaScript tạm dừng việc thực thi mã tuần tự khác. Vì vậy, công cụ JavaScript cần quản lý mọi thứ hiệu quả hơn một chút trong trường hợp này.

Chúng ta có thể phân loại hầu hết các hoạt động JavaScript không đồng bộ với hai kích hoạt chính:

  1. Trình duyệt API/Web API sự kiện hoặc chức năng. Chúng bao gồm các phương pháp như
    function printMe() {
      console.log('print me');
    }
    
    function test() {
      console.log('test');
    }
    
    setTimeout(printMe, 2000);
    test();
    
    5 hoặc trình xử lý sự kiện như Click, Chuột qua, Cuộn và nhiều hơn nữa.
    events or functions. These include methods like
    function printMe() {
      console.log('print me');
    }
    
    function test() {
      console.log('test');
    }
    
    setTimeout(printMe, 2000);
    test();
    
    5, or event handlers like click, mouse over, scroll, and many more.
  2. Hứa hẹn. Một đối tượng JavaScript duy nhất cho phép chúng tôi thực hiện các hoạt động không đồng bộ.. A unique JavaScript object that allows us to perform asynchronous operations.

Đừng lo lắng nếu bạn là người mới hứa. Bạn không cần biết nhiều hơn thế này để theo dõi bài viết này. Vào cuối bài viết, tôi đã cung cấp một số liên kết để bạn có thể bắt đầu học lời hứa theo cách thân thiện nhất với người mới bắt đầu.

Cách xử lý API/API Web của trình duyệt

Trình duyệt API như

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5 và Trình xử lý sự kiện dựa vào các chức năng
function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
7. Một chức năng gọi lại thực thi khi một thao tác không đồng bộ hoàn thành. Dưới đây là một ví dụ về cách hoạt động của hàm
function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5:

function printMe() {
  console.log('print me');
}

setTimeout(printMe, 2000);

Hàm

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5 thực hiện một hàm sau một khoảng thời gian nhất định đã trôi qua. Trong mã trên, văn bản
printMe
test
0 đăng nhập vào bảng điều khiển sau khi trì hoãn 2 giây.

Bây giờ giả sử chúng ta có thêm một vài dòng mã ngay sau hàm

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5 như thế này:

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();

Vì vậy, những gì chúng ta mong đợi sẽ xảy ra ở đây? Bạn nghĩ đầu ra sẽ là gì?

Công cụ JavaScript sẽ đợi trong 2 giây để đi đến việc gọi hàm

printMe
test
2 và xuất ra điều này:

printMe
test

Hoặc nó sẽ quản lý để giữ chức năng gọi lại của

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5 sang một bên và tiếp tục các thực thi khác của nó? Vì vậy, đầu ra có thể là thế này, có lẽ:

test
printMe

Nếu bạn đoán sau này, bạn đúng. Đó là nơi cơ chế không đồng bộ bắt đầu.

Cách thức hoạt động của hàng đợi cuộc gọi lại JavaScript (còn gọi là hàng đợi nhiệm vụ)

JavaScript duy trì hàng đợi các chức năng gọi lại. Nó được gọi là hàng đợi gọi lại hoặc hàng đợi nhiệm vụ. Một cấu trúc dữ liệu hàng đợi là

printMe
test
4. Vì vậy, chức năng gọi lại đầu tiên vào hàng đợi có cơ hội đi ra ngoài trước. Nhưng câu hỏi là:

  • Khi nào động cơ JavaScript đặt nó vào hàng đợi?
  • Khi nào động cơ JavaScript lấy nó ra khỏi hàng đợi?
  • Nó đi đâu khi nó ra khỏi hàng đợi?
  • Quan trọng nhất, làm thế nào để tất cả những điều này liên quan đến phần không đồng bộ của JavaScript?

Whoa, rất nhiều câu hỏi! Hãy tìm ra câu trả lời với sự trợ giúp của hình ảnh sau:

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ

Hình ảnh trên cho thấy

printMe
test
5 thông thường chúng ta đã thấy. Có hai phần bổ sung để theo dõi nếu API trình duyệt (như setTimeout) khởi động và
printMe
test
6S Chức năng gọi lại từ API đó.

Công cụ JavaScript tiếp tục thực thi các chức năng trong ngăn xếp cuộc gọi. Vì nó không đặt hàm gọi lại thẳng vào ngăn xếp, không có câu hỏi nào về bất kỳ mã nào đang chờ/chặn thực thi trong ngăn xếp.

Động cơ tạo ra một

printMe
test
7 để nhìn vào hàng đợi định kỳ để tìm những gì nó cần để kéo từ đó. Nó kéo một chức năng gọi lại từ hàng đợi đến ngăn xếp cuộc gọi khi ngăn xếp trống. Bây giờ hàm gọi lại thực thi nói chung là bất kỳ hàm nào khác trong ngăn xếp. Các vòng lặp tiếp tục. Vòng lặp này nổi tiếng được biết đến với cái tên
printMe
test
8.

Vì vậy, đạo đức của câu chuyện là:

  • Khi API trình duyệt xảy ra, việc đỗ các chức năng gọi lại trong hàng đợi.
  • Tiếp tục thực thi mã như bình thường trong ngăn xếp.
  • Vòng lặp sự kiện kiểm tra xem có chức năng gọi lại trong hàng đợi không.
  • Nếu vậy, hãy kéo chức năng gọi lại từ hàng đợi đến ngăn xếp và thực thi.
  • Tiếp tục vòng lặp.

Được rồi, chúng ta hãy xem nó hoạt động như thế nào với mã bên dưới:

function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();

Mã thực thi chức năng

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5 với chức năng gọi lại
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8. Lưu ý rằng chúng tôi đã cho không chậm trễ với nó. Điều này có nghĩa là chúng tôi mong đợi chức năng
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
8 sẽ thực thi ngay lập tức. Ngay sau khi setTimeout, chúng tôi thực hiện một chức năng khác,
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
9.

Vì vậy, bạn nghĩ đầu ra sẽ là gì? Đây là:

main
f2
f1

Nhưng, bạn có thể nghĩ rằng

test
printMe
3 nên in trước
test
printMe
4 vì chúng tôi không trì hoãn F1 để thực thi. Nhưng không, đó không phải là trường hợp. Hãy nhớ cơ chế
test
printMe
5 mà chúng ta đã thảo luận ở trên? Bây giờ, chúng ta hãy xem nó trong một luồng từng bước cho mã trên.

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ
Vòng lặp sự kiện-Xem thực thi từng bước

Đây là các bước được viết ra:

  1. Hàm
    test
    printMe
    6 được đặt bên trong ngăn xếp cuộc gọi.
  2. Nó có một nhật ký giao diện điều khiển để in từ chính.
    test
    printMe
    7 thực thi và đi ra khỏi ngăn xếp.
  3. API trình duyệt SetTimeout diễn ra.
  4. Hàm gọi lại đặt nó vào hàng đợi gọi lại.
  5. Trong ngăn xếp, việc thực hiện xảy ra như bình thường, do đó
    function f1() {
      // some code
    }
    function f2() {
      // some code
    }
    function f3() {
      // some code
    }
    
    // Invoke the functions one by one
    f1();
    f2();
    f3();
    9 vào ngăn xếp. Nhật ký bảng điều khiển của
    function f1() {
      // some code
    }
    function f2() {
      // some code
    }
    function f3() {
      // some code
    }
    
    // Invoke the functions one by one
    f1();
    f2();
    f3();
    9 thực thi. Cả hai đi ra khỏi ngăn xếp.
  6. test
    printMe
    6 cũng bật ra khỏi ngăn xếp.
  7. Vòng lặp sự kiện nhận ra rằng ngăn xếp cuộc gọi trống và có chức năng gọi lại trong hàng đợi.
  8. Hàm gọi lại
    function f1() {
      // some code
    }
    function f2() {
      // some code
    }
    function f3() {
      // some code
    }
    
    // Invoke the functions one by one
    f1();
    f2();
    f3();
    8 sau đó đi vào ngăn xếp. Thực thi bắt đầu. Nhật ký bảng điều khiển thực thi và
    function f1() {
      // some code
    }
    function f2() {
      // some code
    }
    function f3() {
      // some code
    }
    
    // Invoke the functions one by one
    f1();
    f2();
    f3();
    8 cũng ra khỏi ngăn xếp.
  9. Tại thời điểm này, không có gì khác nằm trong ngăn xếp và hàng đợi để thực hiện thêm.

Tôi hy vọng bây giờ rõ ràng với bạn cách

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
1 của JavaScript hoạt động trong nội bộ. Nhưng đó không phải là tất cả. Chúng ta phải xem xét
function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();
4.

Cách thức xử lý động cơ JavaScript hứa hẹn

Trong JavaScript, những lời hứa là các đối tượng đặc biệt giúp bạn thực hiện các hoạt động không đồng bộ.

Bạn có thể tạo một lời hứa bằng cách sử dụng hàm tạo

function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();
5. Bạn cần phải truyền chức năng
function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();
6 cho nó. Trong chức năng thực thi, bạn xác định những gì bạn muốn làm khi một lời hứa trả về thành công hoặc khi nó gây ra lỗi. Bạn có thể làm điều đó bằng cách gọi các phương thức
function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();
7 và
function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();
8, tương ứng.

Dưới đây là một ví dụ về một lời hứa trong JavaScript:

const promise = new Promise((resolve, reject) =>
        resolve('I am a resolved promise');
);

Sau khi lời hứa được thực hiện, chúng tôi có thể xử lý kết quả bằng phương pháp

function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    
    setTimeout(f1, 0);
    
    f2();
}

main();
9 và bất kỳ lỗi nào với phương thức
main
f2
f1
0.

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
0

Bạn sử dụng lời hứa mỗi khi bạn sử dụng phương thức

main
f2
f1
1 để lấy một số dữ liệu từ cửa hàng.

Vấn đề ở đây là công cụ JavaScript không sử dụng cùng một

main
f2
f1
2 mà chúng ta đã thấy trước đó cho các API trình duyệt. Nó sử dụng một hàng đợi đặc biệt khác được gọi là
main
f2
f1
3.

Hàng đợi công việc trong JavaScript là gì?

Mỗi khi một lời hứa xảy ra trong mã, chức năng thực thi lại vào hàng đợi công việc. Vòng lặp sự kiện hoạt động, như thường lệ, để xem xét hàng đợi nhưng ưu tiên cho các mục

main
f2
f1
4 qua các mục
main
f2
f1
2 khi
function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
5 miễn phí.

Mục trong hàng đợi gọi lại được gọi là

main
f2
f1
7, trong khi mục trong hàng đợi công việc được gọi là
main
f2
f1
8.

Vì vậy, toàn bộ dòng chảy diễn ra như thế này:

  • Đối với mỗi vòng của
    test
    printMe
    5, một nhiệm vụ được hoàn thành trong số
    main
    f2
    f1
    2.
  • Khi nhiệm vụ đó hoàn tất, vòng lặp sự kiện sẽ truy cập
    main
    f2
    f1
    4. Nó hoàn thành tất cả
    const promise = new Promise((resolve, reject) =>
            resolve('I am a resolved promise');
    );
    2 trong hàng đợi công việc trước khi nó xem xét điều tiếp theo.
  • Nếu cả hai hàng đợi đều có các mục tại cùng một thời điểm,
    main
    f2
    f1
    4 sẽ được ưu tiên hơn
    main
    f2
    f1
    2.

Hình ảnh dưới đây cho thấy sự bao gồm của hàng đợi công việc cùng với các mục từ trước khác.

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ

Bây giờ, chúng ta hãy xem một ví dụ để hiểu rõ hơn về chuỗi này:

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
1

Trong mã trên, chúng tôi có chức năng

const promise = new Promise((resolve, reject) =>
        resolve('I am a resolved promise');
);
5 như trước đây, nhưng chúng tôi đã đưa ra một lời hứa ngay sau đó. Bây giờ hãy nhớ tất cả những gì chúng ta đã học và đoán đầu ra.

Nếu câu trả lời của bạn phù hợp với điều này, bạn đã đúng:

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
2

Bây giờ chúng ta hãy xem dòng chảy của hành động:

Hướng dẫn why javascript is synchronous and single - tại sao javascript là đồng bộ và đơn lẻ
Hàng đợi gọi lại so với hàng đợi công việc

Dòng chảy gần giống như trên, nhưng điều quan trọng là phải chú ý cách các mục từ hàng đợi công việc ưu tiên các mục từ hàng đợi nhiệm vụ. Cũng lưu ý rằng nó thậm chí không quan trọng nếu

function printMe() {
  console.log('print me');
}

function test() {
  console.log('test');
}

setTimeout(printMe, 2000);
test();
5 không có độ trễ bằng không. Nó luôn luôn là về hàng đợi công việc xuất hiện trước hàng đợi gọi lại.

Được rồi, chúng ta đã học được mọi thứ chúng ta cần để hiểu thực thi đồng bộ và không đồng bộ trong JavaScript.

Đây là một bài kiểm tra cho bạn!

Hãy kiểm tra sự hiểu biết của bạn bằng cách làm một bài kiểm tra. Đoán đầu ra của mã sau và áp dụng tất cả các kiến ​​thức chúng tôi đã thu được cho đến nay:

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
3

Đây là đầu ra dự kiến:

function f1() {
  // some code
}
function f2() {
  // some code
}
function f3() {
  // some code
}

// Invoke the functions one by one
f1();
f2();
f3();
4

Bạn có muốn nhiều câu đố như vậy không? Đi qua kho lưu trữ này để thực hành nhiều bài tập hơn.

Trong trường hợp bạn bị mắc kẹt hoặc cần bất kỳ sự làm rõ nào, DM của tôi luôn mở trên Twitter.

Tóm tắt

Để tóm tắt:

  • Công cụ JavaScript sử dụng cấu trúc dữ liệu ngăn xếp để theo dõi các chức năng hiện đang được thực hiện. Ngăn xếp được gọi là ngăn xếp thực thi chức năng.
  • Ngăn xếp thực thi chức năng (AKA Call Stack) thực thi các hàm theo tuần tự, từng dòng, từng người một.
  • Trình duyệt/API Web sử dụng các chức năng gọi lại để hoàn thành các tác vụ khi thực hiện hoạt động/độ trễ không đồng bộ. Hàm gọi lại được đặt trong hàng đợi gọi lại.
  • Các chức năng thực thi hứa hẹn được đặt trong hàng đợi công việc.
  • Đối với mỗi vòng lặp của vòng lặp sự kiện, một tác vụ macro được hoàn thành từ hàng đợi gọi lại.
  • Khi nhiệm vụ đó hoàn tất, vòng lặp sự kiện sẽ đến hàng đợi công việc. Nó hoàn thành tất cả các nhiệm vụ vi mô trong hàng đợi công việc trước khi nó tìm kiếm điều tiếp theo.
  • Nếu cả hai hàng đợi có được các mục tại cùng một thời điểm, hàng đợi công việc được ưu tiên so với hàng đợi gọi lại.

Trước khi chúng ta kết thúc ...

Đó là tất cả cho bây giờ. Tôi hy vọng bạn đã tìm thấy bài viết này sâu sắc và nó giúp bạn hiểu các khái niệm đồng bộ với sự không đồng bộ của JavaScript tốt hơn.

Hãy kết nối. Bạn có thể theo dõi tôi trên Twitter (@tapasadhikary), kênh YouTube của tôi và GitHub (ATAPAS).

Như đã hứa trước đây, đây là một vài bài viết bạn có thể thấy hữu ích,

  • Lời hứa của JavaScript - Giải thích như tôi năm
  • Chuỗi lời hứa JavaScript - Nghệ thuật xử lý lời hứa
  • JavaScript async và chờ đợi - bằng tiếng Anh đơn giản, làm ơn
  • Giới thiệu Promiviz - Trực quan hóa và tìm hiểu API hứa hẹn JavaScript


Học mã miễn phí. Chương trình giảng dạy 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

Tại sao JavaScript là đồng bộ và một luồng đơn?

JavaScript là ngôn ngữ đơn luồng vì trong khi chạy mã trên một luồng, nó có thể thực sự dễ thực hiện vì chúng ta không phải đối phó với các kịch bản phức tạp phát sinh trong môi trường đa luồng như bế tắc. Vì, JavaScript là một ngôn ngữ đơn luồng, nó có bản chất đồng bộ.while running code on a single thread, it can be really easy to implement as we don't have to deal with the complicated scenarios that arise in the multi-threaded environment like deadlock. Since, JavaScript is a single-threaded language, it is synchronous in nature.

Tại sao JavaScript không đồng bộ hoặc đồng bộ?

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ù!only one operation can be in progress at a time. That's not the entire story, though!

Tại sao JavaScript được gọi là một luồng?

JavaScript là một ngôn ngữ ren duy nhất có thể không chặn.Một luồng đơn có nghĩa là nó chỉ có một ngăn xếp cuộc gọi.Bất cứ điều gì nằm trên đỉnh của ngăn xếp cuộc gọi được chạy đầu tiên.Trong chương trình trên, các chức năng được chạy tuần tự.

Có phải JavaScript thực sự là một luồng?

Trong bối cảnh lập trình, song song là việc sử dụng nhiều luồng trong một hệ điều hành.Các thói quen có thể chạy cùng một lúc bất kể thứ tự thực hiện.JavaScript, tuy nhiên, là một luồng đơn và chỉ có một dòng mã có thể được thực thi tại bất kỳ thời điểm nào.JavaScript, however, is single threaded and only one line of code can be executed at any given time.