JavaScript là đồng bộ hay không đồng bộ?

Khi sử dụng hàm JavaScript setTimeout(), bạn có thể chỉ định hàm gọi lại sẽ được thực thi khi hết thời gian chờ

Thí dụ

setTimeout(myFunction, 3000);

hàm myFunction() {
tài liệu. getElementById("bản trình diễn"). internalHTML = "Anh yêu em. “;
}

Tự mình thử »

Trong ví dụ trên, myFunction được sử dụng như một cuộc gọi lại

myFunction được chuyển đến setTimeout() như một đối số

3000 là số mili giây trước khi hết thời gian, vì vậy myFunction() sẽ được gọi sau 3 giây

Ghi chú

Khi bạn chuyển một hàm làm đối số, hãy nhớ không sử dụng dấu ngoặc đơn

Đúng. setTimeout(myFunction, 3000);

Sai. setTimeout(myFunction(), 3000);

Thay vì chuyển tên của một hàm làm đối số cho một hàm khác, thay vào đó, bạn luôn có thể chuyển toàn bộ hàm

Thí dụ

setTimeout(function() { myFunction("Anh yeu em. "); }, 3000);

hàm myFunction(giá trị) {
tài liệu. getElementById("bản trình diễn"). bên trongHTML = giá trị;
}

Tự mình thử »

Trong ví dụ trên, function(){ myFunction("I love You !!!"); } được sử dụng như một cuộc gọi lại. Nó là một chức năng hoàn chỉnh. Hàm hoàn chỉnh được chuyển đến setTimeout() làm đối số

3000 là số mili giây trước khi hết thời gian, vì vậy myFunction() sẽ được gọi sau 3 giây



Đang chờ khoảng thời gian

Khi sử dụng hàm JavaScript myCalculator()0, bạn có thể chỉ định hàm gọi lại sẽ được thực thi cho mỗi khoảng thời gian

Thí dụ

setInterval(myFunction, 1000);

hàm myFunction() {
hãy để d = Ngày mới ();
tài liệu. getElementById("bản trình diễn"). bên trongHTML=
đ. getHours() + ". " +
đ. getMinutes() + ". " +
đ. getSeconds();
}

Tự mình thử »

Trong ví dụ trên, myFunction được sử dụng như một cuộc gọi lại

myFunction được chuyển đến myCalculator()0 như một đối số

1000 là số mili giây giữa các khoảng thời gian, do đó, myFunction() sẽ được gọi mỗi giây


Các lựa chọn thay thế gọi lại

Với lập trình không đồng bộ, các chương trình JavaScript có thể bắt đầu các tác vụ chạy dài và tiếp tục chạy song song các tác vụ khác

Tuy nhiên, các chương trình không đồng bộ rất khó viết và khó gỡ lỗi

Do đó, hầu hết các phương thức JavaScript không đồng bộ hiện đại không sử dụng lệnh gọi lại. Thay vào đó, trong JavaScript, lập trình không đồng bộ được giải quyết bằng Promises

Trong bài viết này, chúng tôi sẽ giải thích lập trình bất đồng bộ là gì, tại sao chúng tôi cần nó và thảo luận ngắn gọn về một số cách các chức năng không đồng bộ đã được triển khai trong lịch sử trong JavaScript

điều kiện tiên quyết. Trình độ máy tính cơ bản, hiểu biết hợp lý về các nguyên tắc cơ bản của JavaScript, bao gồm các chức năng và trình xử lý sự kiện. Khách quan. Để làm quen với JavaScript không đồng bộ là gì, nó khác với JavaScript đồng bộ như thế nào và tại sao chúng ta cần nó

Lập trình không đồng bộ là một kỹ thuật cho phép chương trình của bạn bắt đầu một tác vụ có khả năng chạy dài và vẫn có thể phản hồi các sự kiện khác trong khi tác vụ đó chạy, thay vì phải đợi cho đến khi tác vụ đó kết thúc. Khi nhiệm vụ đó đã hoàn thành, chương trình của bạn sẽ hiển thị kết quả

Nhiều chức năng do trình duyệt cung cấp, đặc biệt là những chức năng thú vị nhất, có thể mất nhiều thời gian và do đó, không đồng bộ. Ví dụ

  • Thực hiện các yêu cầu HTTP bằng cách sử dụng
    function makeGreeting(name) {
      return `Hello, my name is ${name}!`;
    }
    
    const name = 'Miriam';
    const greeting = makeGreeting(name);
    console.log(greeting);
    // "Hello, my name is Miriam!"
    
    2
  • Truy cập máy ảnh hoặc micrô của người dùng bằng cách sử dụng
    function makeGreeting(name) {
      return `Hello, my name is ${name}!`;
    }
    
    const name = 'Miriam';
    const greeting = makeGreeting(name);
    console.log(greeting);
    // "Hello, my name is Miriam!"
    
    3
  • Yêu cầu người dùng chọn tệp bằng cách sử dụng
    function makeGreeting(name) {
      return `Hello, my name is ${name}!`;
    }
    
    const name = 'Miriam';
    const greeting = makeGreeting(name);
    console.log(greeting);
    // "Hello, my name is Miriam!"
    
    4

Vì vậy, mặc dù bạn có thể không phải thực hiện các chức năng không đồng bộ của riêng mình thường xuyên, nhưng rất có thể bạn cần sử dụng chúng một cách chính xác

Trong bài viết này, chúng ta sẽ bắt đầu bằng cách xem xét vấn đề với các hàm đồng bộ chạy dài, khiến cho việc lập trình không đồng bộ trở nên cần thiết

Hãy xem xét đoạn mã sau

const name = 'Miriam';
const greeting = `Hello, my name is ${name}!`;
console.log(greeting);
// "Hello, my name is Miriam!"

mã này

  1. Khai báo một chuỗi có tên là
    function makeGreeting(name) {
      return `Hello, my name is ${name}!`;
    }
    
    const name = 'Miriam';
    const greeting = makeGreeting(name);
    console.log(greeting);
    // "Hello, my name is Miriam!"
    
    5
  2. Khai báo một chuỗi khác có tên là
    function makeGreeting(name) {
      return `Hello, my name is ${name}!`;
    }
    
    const name = 'Miriam';
    const greeting = makeGreeting(name);
    console.log(greeting);
    // "Hello, my name is Miriam!"
    
    6, sử dụng
    function makeGreeting(name) {
      return `Hello, my name is ${name}!`;
    }
    
    const name = 'Miriam';
    const greeting = makeGreeting(name);
    console.log(greeting);
    // "Hello, my name is Miriam!"
    
    5
  3. Xuất lời chào ra bảng điều khiển JavaScript

Chúng ta nên lưu ý ở đây rằng trình duyệt duyệt từng dòng một của chương trình một cách hiệu quả, theo thứ tự chúng ta đã viết nó. Tại mỗi điểm, trình duyệt đợi dòng hoàn thành công việc của nó trước khi chuyển sang dòng tiếp theo. Nó phải làm điều này bởi vì mỗi dòng phụ thuộc vào công việc được thực hiện trong các dòng trước

Điều đó làm cho chương trình này trở thành một chương trình đồng bộ. Nó vẫn sẽ đồng bộ ngay cả khi chúng ta gọi một chức năng riêng biệt, như thế này

function makeGreeting(name) {
  return `Hello, my name is ${name}!`;
}

const name = 'Miriam';
const greeting = makeGreeting(name);
console.log(greeting);
// "Hello, my name is Miriam!"

Ở đây,

function makeGreeting(name) {
  return `Hello, my name is ${name}!`;
}

const name = 'Miriam';
const greeting = makeGreeting(name);
console.log(greeting);
// "Hello, my name is Miriam!"
8 là một hàm đồng bộ vì người gọi phải đợi hàm hoàn thành công việc và trả về một giá trị trước khi người gọi có thể tiếp tục

Nếu chức năng đồng bộ mất nhiều thời gian thì sao?

Chương trình bên dưới sử dụng thuật toán rất kém hiệu quả để tạo nhiều số nguyên tố lớn khi người dùng nhấp vào nút "Tạo số nguyên tố". Số lượng số nguyên tố do người dùng chỉ định càng cao thì thao tác sẽ càng mất nhiều thời gian

<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>

const MAX_PRIME = 1000000;

function isPrime(n) {
  for (let i = 2; i <= Math.sqrt(n); i++) {
    if (n % i === 0) {
      return false;
    }
  }
  return n > 1;
}

const random = (max) => Math.floor(Math.random() * max);

function generatePrimes(quota) {
  const primes = [];
  while (primes.length < quota) {
    const candidate = random(MAX_PRIME);
    if (isPrime(candidate)) {
      primes.push(candidate);
    }
  }
  return primes;
}

const quota = document.querySelector('#quota');
const output = document.querySelector('#output');

document.querySelector('#generate').addEventListener('click', () => {
  const primes = generatePrimes(quota.value);
  output.textContent = `Finished generating ${quota.value} primes!`;
});

document.querySelector('#reload').addEventListener('click', () => {
  document.location.reload();
});

Hãy thử nhấp vào "Tạo số nguyên tố". Tùy thuộc vào tốc độ máy tính của bạn, có thể sẽ mất vài giây trước khi chương trình hiển thị thông báo "Đã hoàn tất. " thông điệp

Ví dụ tiếp theo giống như ví dụ trước, ngoại trừ chúng tôi đã thêm một hộp văn bản để bạn nhập vào. Lần này, hãy nhấp vào "Tạo số nguyên tố" và thử nhập vào hộp văn bản ngay sau đó

Bạn sẽ thấy rằng trong khi chức năng

function makeGreeting(name) {
  return `Hello, my name is ${name}!`;
}

const name = 'Miriam';
const greeting = makeGreeting(name);
console.log(greeting);
// "Hello, my name is Miriam!"
9 của chúng tôi đang chạy, chương trình của chúng tôi hoàn toàn không phản hồi. bạn không thể nhập bất cứ thứ gì, nhấp vào bất cứ thứ gì hoặc làm bất cứ điều gì khác

<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<textarea id="user-input" rows="5" cols="62">
Try typing in here immediately after pressing "Generate primes"
textarea>

<div id="output">div>

textarea {
  display: block;
  margin: 1rem 0;
}

const MAX_PRIME = 1000000;

function isPrime(n) {
  for (let i = 2; i <= Math.sqrt(n); i++) {
    if (n % i === 0) {
      return false;
    }
  }
  return n > 1;
}

const random = (max) => Math.floor(Math.random() * max);

function generatePrimes(quota) {
  const primes = [];
  while (primes.length < quota) {
    const candidate = random(MAX_PRIME);
    if (isPrime(candidate)) {
      primes.push(candidate);
    }
  }
  return primes;
}

const quota = document.querySelector('#quota');
const output = document.querySelector('#output');

document.querySelector('#generate').addEventListener('click', () => {
  const primes = generatePrimes(quota.value);
  output.textContent = `Finished generating ${quota.value} primes!`;
});

document.querySelector('#reload').addEventListener('click', () => {
  document.location.reload();
});

Đây là vấn đề cơ bản với các chức năng đồng bộ chạy dài. Những gì chúng tôi cần là một cách để chương trình của chúng tôi

  1. Bắt đầu một hoạt động dài hạn bằng cách gọi một chức năng
  2. Để chức năng đó bắt đầu hoạt động và quay lại ngay lập tức, để chương trình của chúng tôi vẫn có thể phản hồi các sự kiện khác
  3. Thông báo cho chúng tôi về kết quả của hoạt động khi nó hoàn thành

Đó chính xác là những gì các chức năng không đồng bộ có thể làm. Phần còn lại của mô-đun này giải thích cách chúng được triển khai trong JavaScript

Mô tả mà chúng ta vừa thấy về các hàm không đồng bộ có thể nhắc bạn về các trình xử lý sự kiện và nếu đúng như vậy thì bạn đã đúng. Trình xử lý sự kiện thực sự là một dạng lập trình không đồng bộ. bạn cung cấp một chức năng (trình xử lý sự kiện) sẽ được gọi, không phải ngay lập tức mà bất cứ khi nào sự kiện xảy ra. Nếu "sự kiện" là "hoạt động không đồng bộ đã hoàn thành", thì sự kiện đó có thể được sử dụng để thông báo cho người gọi về kết quả của một lệnh gọi hàm không đồng bộ

Một số API không đồng bộ ban đầu đã sử dụng các sự kiện theo cách này. API

<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>
0 cho phép bạn thực hiện các yêu cầu HTTP tới máy chủ từ xa bằng JavaScript. Vì quá trình này có thể mất nhiều thời gian, nên đây là một API không đồng bộ và bạn được thông báo về tiến độ và khả năng hoàn thành cuối cùng của một yêu cầu bằng cách đính kèm trình xử lý sự kiện vào đối tượng
<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>
0

Ví dụ sau đây cho thấy điều này trong hành động. Nhấn "Click to start request" để gửi yêu cầu. Chúng tôi tạo một

<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>
0 mới và lắng nghe sự kiện
<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>
3 của nó. Trình xử lý ghi nhật ký "Đã hoàn tất. " thông báo cùng với mã trạng thái

Sau khi thêm trình lắng nghe sự kiện, chúng tôi gửi yêu cầu. Lưu ý rằng sau này, chúng tôi có thể đăng nhập "Yêu cầu XHR đã bắt đầu". nghĩa là, chương trình của chúng tôi có thể tiếp tục chạy trong khi yêu cầu đang diễn ra và trình xử lý sự kiện của chúng tôi sẽ được gọi khi yêu cầu hoàn tất

<button id="xhr">Click to start requestbutton>
<button id="reload">Reloadbutton>

<pre readonly class="event-log">pre>

pre {
  display: block;
  margin: 1rem 0;
}

const log = document.querySelector('.event-log');

document.querySelector('#xhr').addEventListener('click', () => {
  log.textContent = '';

  const xhr = new XMLHttpRequest();

  xhr.addEventListener('loadend', () => {
    log.textContent = `${log.textContent}Finished with status: ${xhr.status}`;
  });

  xhr.open('GET', 'https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json');
  xhr.send();
  log.textContent = `${log.textContent}Started XHR request\n`;});

document.querySelector('#reload').addEventListener('click', () => {
  log.textContent = '';
  document.location.reload();
});

Điều này giống như các trình xử lý sự kiện mà chúng ta đã gặp trong mô-đun trước, ngoại trừ việc thay vì sự kiện là hành động của người dùng, chẳng hạn như người dùng nhấp vào nút, thì sự kiện này là sự thay đổi trạng thái của một số đối tượng

Trình xử lý sự kiện là một loại gọi lại cụ thể. Một cuộc gọi lại chỉ là một chức năng được truyền vào một chức năng khác, với mong muốn rằng cuộc gọi lại sẽ được gọi vào thời điểm thích hợp. Như chúng ta vừa thấy, các cuộc gọi lại từng là cách chính để triển khai các chức năng không đồng bộ trong JavaScript

Tuy nhiên, mã dựa trên cuộc gọi lại có thể khó hiểu khi bản thân cuộc gọi lại phải gọi các hàm chấp nhận cuộc gọi lại. Đây là tình huống phổ biến nếu bạn cần thực hiện một số thao tác chia nhỏ thành một loạt các chức năng không đồng bộ. Ví dụ, hãy xem xét những điều sau đây

function makeGreeting(name) {
  return `Hello, my name is ${name}!`;
}

const name = 'Miriam';
const greeting = makeGreeting(name);
console.log(greeting);
// "Hello, my name is Miriam!"
0

Ở đây, chúng tôi có một thao tác được chia thành ba bước, trong đó mỗi bước phụ thuộc vào bước cuối cùng. Trong ví dụ của chúng tôi, bước đầu tiên thêm 1 vào đầu vào, bước thứ hai thêm 2 và bước thứ ba thêm 3. Bắt đầu với đầu vào là 0, kết quả cuối cùng là 6 (0 + 1 + 2 + 3). Là một chương trình đồng bộ, điều này rất đơn giản. Nhưng nếu chúng ta triển khai các bước bằng cách sử dụng lệnh gọi lại thì sao?

function makeGreeting(name) {
  return `Hello, my name is ${name}!`;
}

const name = 'Miriam';
const greeting = makeGreeting(name);
console.log(greeting);
// "Hello, my name is Miriam!"
1

Bởi vì chúng tôi phải gọi các cuộc gọi lại bên trong các cuộc gọi lại, chúng tôi nhận được một hàm

<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>
4 được lồng sâu, khó đọc và gỡ lỗi hơn nhiều. Điều này đôi khi được gọi là "địa ngục gọi lại" hoặc "kim tự tháp diệt vong" (vì vết lõm trông giống như một kim tự tháp trên mặt của nó)

Khi chúng ta lồng các cuộc gọi lại như thế này, nó cũng có thể rất khó xử lý lỗi. thường thì bạn phải xử lý lỗi ở từng cấp của “kim tự tháp”, thay vì chỉ xử lý lỗi một lần ở cấp cao nhất

Vì những lý do này, hầu hết các API không đồng bộ hiện đại không sử dụng lệnh gọi lại. Thay vào đó, nền tảng của lập trình bất đồng bộ trong JavaScript là

<label for="quota">Number of primes:label>
<input type="text" id="quota" name="quota" value="1000000" />

<button id="generate">Generate primesbutton>
<button id="reload">Reloadbutton>

<div id="output">div>
5, và đó là chủ đề của bài viết tiếp theo

JavaScript là phương tiện không đồng bộ hay đồng bộ?

Phần giới thiệu. về cơ bản, JavaScript là một đồng bộ , chặn, ngôn ngữ đơn luồng. Điều đó chỉ có nghĩa là tại một thời điểm chỉ có một hoạt động có thể được tiến hành. Đó không phải là toàn bộ câu chuyện, mặc dù.

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

Nếu bạn đã học JavaScript được một thời gian, thì có lẽ bạn đã từng nghe thuật ngữ "không đồng bộ" trước đây. Điều này là do JavaScript là một ngôn ngữ không đồng bộ. Nhưng điều đó thực sự có ý nghĩa gì?

JavaScript nào không đồng bộ?

Lập trình không đồng bộ là một kỹ thuật cho phép chương trình của bạn bắt đầu một tác vụ có khả năng chạy dài và vẫn có thể phản hồi các sự kiện khác trong khi tác vụ đó chạy, thay vì phải đợi cho đến khi tác vụ đó kết thúc. Khi nhiệm vụ đó đã hoàn thành, chương trình của bạn sẽ hiển thị kết quả

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

JavaScript được đồng bộ theo mặc định và là luồng đơn. Điều này có nghĩa là mã không thể tạo chủ đề mới và nó sẽ thực thi khối mã của bạn theo thứ tự sau khi cẩu