Hướng dẫn wait in javascript - đợi trong javascript

Nhiều ngôn ngữ lập trình có hàm

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
3 sẽ trì hoãn việc thực hiện chương trình trong một số giây nhất định. Tuy nhiên, chức năng này không có trong JavaScript do bản chất không đồng bộ của nó. Trong bài viết này, chúng tôi sẽ xem xét ngắn gọn lý do tại sao điều này có thể, sau đó làm thế nào chúng ta có thể tự thực hiện chức năng
fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
3.

Hiểu mô hình thực thi JavaScript từ

Trước khi chúng tôi đi, điều quan trọng là đảm bảo chúng tôi hiểu chính xác mô hình thực thi JavaScript.

Xem xét mã Ruby sau:

require 'net/http'
require 'json'

url = 'https://api.github.com/users/jameshibbard'
uri = URI(url)
response = JSON.parse(Net::HTTP.get(uri))
puts response['public_repos']
puts "Hello!"

Như người ta có thể mong đợi, mã này đưa ra yêu cầu cho API GitHub để tìm nạp dữ liệu người dùng của tôi. Sau đó, nó phân tích phản hồi, xuất trình số lượng repo công khai được quy cho tài khoản GitHub của tôi và cuối cùng in ra Hello Hello! lên màn hình. Thực thi đi từ trên xuống dưới.

Tương phản với phiên bản JavaScript tương đương:

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");

Nếu bạn chạy mã này, nó sẽ xuất ra Hello Hello! Đối với màn hình, sau đó số lượng repos công khai được quy cho tài khoản GitHub của tôi.

Điều này là do tìm nạp dữ liệu từ API là một hoạt động không đồng bộ trong JavaScript. Trình thông dịch JavaScript sẽ gặp lệnh

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
5 và gửi yêu cầu. Tuy nhiên, nó sẽ không chờ đợi yêu cầu hoàn thành. Thay vào đó, nó sẽ tiếp tục trên đường của nó, đầu ra là Hello Hello! Đối với bảng điều khiển, sau đó khi yêu cầu trả về một vài trăm mili giây sau đó, nó sẽ xuất ra số lượng repos.

Nếu bất kỳ ai trong số này là tin tức cho bạn, bạn nên xem cuộc nói chuyện hội nghị tuyệt vời này: Dù sao thì cái quái gì là vòng lặp sự kiện ?.

Bạn có thể không thực sự cần một chức năng ngủ của JS

Bây giờ chúng ta đã hiểu rõ hơn về mô hình thực thi JavaScript, hãy để Lôi xem cách JavaScript xử lý sự chậm trễ và các hoạt động không đồng bộ.

Tạo độ trễ đơn giản bằng cách sử dụng fetch('https://api.github.com/users/jameshibbard') .then(res => res.json()) .then(json => console.log(json.public_repos)); console.log("Hello!"); 6

Cách tiêu chuẩn để tạo độ trễ trong JavaScript là sử dụng phương pháp

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
6 của nó. Ví dụ:

console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);

Điều này sẽ đăng nhập vào Hello Hello vào bảng điều khiển, sau đó làm cho JavaScript đợi 5 giây, sau đó đăng nhập thế giới! đến giao diện điều khiển. Và trong nhiều trường hợp, điều này là đủ: làm điều gì đó, chờ đợi, sau đó làm một cái gì đó khác. Sắp xếp!

Tuy nhiên, xin lưu ý rằng

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
6 là một phương pháp không đồng bộ. Hãy thử thay đổi mã trước như vậy:

console.log("Hello");
setTimeout(() => { console.log("World!"); }, 5000);
console.log("Goodbye!");

Nó sẽ đăng nhập:

Hello
Goodbye!
World!

Chờ mọi thứ với SetTimeout

Nó cũng có thể sử dụng

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
6 (hoặc anh em họ
console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
0) để làm cho JavaScript hoặc TypeScript đợi cho đến khi một điều kiện được đáp ứng. Ví dụ: ở đây, cách bạn có thể sử dụng
fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
6 để chờ một yếu tố nhất định xuất hiện trên trang web:

function pollDOM () {
  const el = document.querySelector('my-element');

  if (el.length) {
    // Do something with el
  } else {
    setTimeout(pollDOM, 300); // try again in 300 milliseconds
  }
}

pollDOM();

Điều này giả định phần tử sẽ xuất hiện tại một số điểm. Nếu bạn không chắc chắn rằng trường hợp đó, bạn sẽ cần xem xét việc hủy bộ đếm thời gian (sử dụng

console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
2 hoặc
console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
3).

Nếu bạn muốn tìm hiểu thêm về phương pháp JavaScript từ

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
6, vui lòng tham khảo hướng dẫn của chúng tôi có rất nhiều ví dụ để giúp bạn đi.

Kiểm soát dòng chảy trong JavaScript hiện đại

Khi viết JavaScript, chúng ta thường cần làm cho JS chờ đợi điều gì đó xảy ra (ví dụ: dữ liệu được tìm nạp từ API), sau đó làm điều gì đó để trả lời (chẳng hạn như cập nhật giao diện người dùng để hiển thị dữ liệu).

Ví dụ trên sử dụng chức năng gọi lại ẩn danh cho mục đích này, nhưng nếu bạn cần chờ nhiều điều xảy ra, cú pháp nhanh chóng trở nên khá sởn gai ốc và bạn sẽ kết thúc trong cuộc gọi lại địa ngục.

May mắn thay, ngôn ngữ đã phát triển đáng kể trong vài năm qua và bây giờ cung cấp cho chúng ta các cấu trúc mới để tránh điều này.

Ví dụ: sử dụng Async đang chờ đợi, chúng tôi có thể viết lại mã ban đầu để tìm nạp thông tin từ API GitHub:

(async () => {
  const res = await fetch(`https://api.github.com/users/jameshibbard`);
  const json = await res.json();
  console.log(json.public_repos);
  console.log("Hello!");
})();

Bây giờ mã thực thi từ trên xuống dưới. Trình thông dịch JavaScript chờ đợi yêu cầu mạng hoàn thành và số lượng repos công khai được ghi lại trước, sau đó là Hello Hello! thông điệp.

Nếu đây là loại điều mà bạn đang cố gắng thực hiện, tôi khuyến khích bạn đọc bài viết của chúng tôi kiểm soát dòng chảy trong JS hiện đại: gọi lại để hứa hẹn với ASYNC/đang chờ đợi.

Mang giấc ngủ cho JavaScript bản địa

Nếu bạn vẫn còn với tôi, thì tôi đoán bạn đã thiết lập khá nhiều việc chặn luồng thực thi đó và khiến JavaScript chờ đợi nó.

Đây là cách bạn có thể làm điều đó:

function sleep(milliseconds) {
  const date = Date.now();
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

console.log("Hello");
sleep(2000);
console.log("World!");

Đúng như dự đoán, điều này sẽ đăng nhập vào Hello Hello, tạm dừng trong hai giây, sau đó đăng nhập thế giới!

Nó hoạt động bằng cách sử dụng phương thức ngày. Sau đó, nó tạo ra một biến

console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
6 trống, trước khi nhập vòng lặp
console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
7. Trong vòng lặp, nó liên tục nhận được số mili giây đã trôi qua kể từ ngày 1 tháng 1 năm 1970 và gán giá trị cho biến
console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
6 được khai báo trước đó. Vòng lặp sẽ tiếp tục đi trong khi sự khác biệt giữa
console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
5 và
console.log("Hello");
setTimeout(() => {  console.log("World!"); }, 5000);
6 nhỏ hơn độ trễ JS mong muốn trong mili giây.

Công việc được thực hiện, phải không? Cũng không hoàn toàn…

Một chức năng ngủ tốt hơn

Có thể mã này thực hiện chính xác những gì bạn đã hy vọng, nhưng hãy lưu ý, nó có một bất lợi lớn: vòng lặp sẽ chặn luồng thực thi JavaScript và đảm bảo rằng không ai có thể tương tác với chương trình của bạn cho đến khi kết thúc. Nếu bạn cần một sự chậm trễ lớn, có một cơ hội mà nó thậm chí có thể làm hỏng mọi thứ hoàn toàn.

Vậy lam gi?

Chà, nó cũng có thể kết hợp các kỹ thuật đã học trước đó trong bài viết để tạo ra một chức năng giấc ngủ ít xâm nhập hơn:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

console.log("Hello");
sleep(2000).then(() => { console.log("World!"); });

Mã này sẽ đăng nhập vào Hello Hello, chờ hai giây, sau đó đăng nhập thế giới! Theo mui xe, chúng tôi sử dụng phương pháp

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
6 để giải quyết một lời hứa sau một số mili giây nhất định.

Lưu ý rằng chúng tôi cần sử dụng gọi lại

console.log("Hello");
setTimeout(() => { console.log("World!"); }, 5000);
console.log("Goodbye!");
2 để đảm bảo tin nhắn thứ hai được ghi lại với độ trễ. Chúng ta cũng có thể chuỗi các cuộc gọi lại nhiều hơn vào đầu tiên:

console.log('Hello')
sleep(2000)
  .then(() => console.log('world!'))
  .then(() => sleep(2000))
  .then(() => console.log('Goodbye!'))

Điều này hoạt động, nhưng tôi không phải là người hâm mộ lớn nhất trong tất cả các ____33. Chúng ta có thể trở nên đẹp mắt bằng cách sử dụng

console.log("Hello");
setTimeout(() => { console.log("World!"); }, 5000);
console.log("Goodbye!");
4:

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
0

Điều này trông đẹp hơn, nhưng có nghĩa là bất kỳ mã nào đang sử dụng hàm

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
3 cần phải được đánh dấu là
console.log("Hello");
setTimeout(() => { console.log("World!"); }, 5000);
console.log("Goodbye!");
6.

Xem bút yllqjrx bằng sitePoint (@SitePoint) trên CodePen.
yLLQJrX by SitePoint (@SitePoint)
on CodePen.

Tất nhiên, cả hai phương pháp này vẫn có nhược điểm (hoặc tính năng) mà chúng không tạm dừng toàn bộ thực thi chương trình. Chỉ có chức năng của bạn ngủ:

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log("Hello!");
1

Mã trên ghi lại như sau:

Hello
Goodbye!
World!

Sự kết luận

Các vấn đề về thời gian trong JavaScript là nguyên nhân của nhiều vấn đề đau đầu của nhà phát triển và cách bạn đối phó với chúng phụ thuộc vào những gì bạn đang cố gắng đạt được.

Mặc dù một chức năng giấc ngủ có mặt trong nhiều ngôn ngữ khác, tôi đã khuyến khích bạn nắm lấy bản chất không đồng bộ của JavaScript và cố gắng không chiến đấu với ngôn ngữ. Nó thực sự khá đẹp khi bạn quen với nó.

Phát triển sự hiểu biết sâu sắc hơn về JavaScript với JavaScript: Novice to Ninja. Cuốn sách toàn diện này bao gồm ngôn ngữ từ đầu, bao gồm cả cú pháp ES6+ mới nhất.

Ngoài ra, bằng cách đọc thêm, hãy xem các liên kết này, đã truyền cảm hứng cho một số mã trong bài viết này:

  • Ngủ trong JavaScript - Sự chậm trễ giữa các hành động
  • Phiên bản JavaScript của Sleep () là gì?

Nếu bạn có bất kỳ câu hỏi nào, vui lòng truy cập Diễn đàn SitePoint và bắt đầu một cuộc thảo luận.