Trì hoãn, Ngủ, Tạm dừng và Chờ trong JavaScript – SitePoint

[ad_1]

        

Nhiều ngôn ngữ lập trình có chức năng ngủ sẽ trì hoãn việc thực thi chương trình trong một số giây nhất định. Chức năng này không có trong JavaScript, tuy nhiên, do tính 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ể xảy ra, sau đó làm thế nào chúng ta có thể tự thực hiện chức năng .

Chúng tôi đã viết lại hướng dẫn phổ biến này từ đầu để cung cấp lời khuyên tốt nhất và cập nhật nhất. Bài viết này đã được cập nhật vào tháng 11 năm 2019.

Tìm hiểu mô hình thực thi JavaScript JavaScript

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

Hãy xem xét mã Ruby sau:

  yêu cầu 'mạng / http'
yêu cầu 'json'

url = 'https://api.github.com/users/jameshibbard'
uri = URI (url)
hồi đáp = JSON.parse (Net :: HTTP.get (uri))
đặt câu trả lời ['public_repos']
đặt "Xin chào!"
 

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

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

  tìm nạp ('https://api.github.com/users/jameshibbard')
  .then (res => res.json ())
  .then (json => console.log (json.public_Vpose));
console.log ("Xin chào!");
 

Nếu bạn chạy mã này, nó sẽ xuất ra Hello Hello! Cho 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 tìm nạp và gửi yêu cầu. Nó sẽ chứ không phải tuy nhiên, hãy đợi yêu cầu hoàn thành. Thay vào đó, nó sẽ tiếp tục trên đường đi, xuất ra Hello Hello! Hiện lên bảng điều khiển, sau đó khi yêu cầu trả về vài trăm mili giây sau, nó sẽ xuất ra số lượng repos.

Nếu bất kỳ điều nào trong số này là tin tức với bạn, bạn nên xem cuộc hội thảo xuất sắc này: Dù sao thì vòng lặp sự kiện là gì?

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

Bây giờ chúng ta đã hiểu rõ hơn về mô hình thực thi JavaScript, hãy để có một cái nhìn về 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 setTimeout

Cách tiêu chuẩn để tạo độ trễ trong JavaScript là sử dụng phương thức setTimeout . Ví dụ:

  console.log ("Xin chào");
setTimeout (() => {console.log ("Thế giới!");}, 2000);
 

. Sắp xếp!

Tuy nhiên, xin lưu ý rằng setTimeout là một phương pháp không đồng bộ. Hãy thử thay đổi mã trước đó như sau:

  console.log ("Xin chào");
setTimeout (() => {console.log ("Thế giới!");}, 2000);
console.log ("Tạm biệt!");
 

Nó sẽ đăng nhập:

  Xin chào
Tạm biệt!
Thế giới!
 

Chờ đợi mọi thứ với setTimeout

Nó cũng có thể sử dụng setTimeout (hoặc anh em họ của nó setInterval ) để giữ JavaScript chờ cho đến khi điều kiện được đáp ứng. Ví dụ: ở đây, cách bạn có thể sử dụng setTimeout để chờ một yếu tố nào đó xuất hiện trên trang web:

  chức năng pollDOM () {
  const el = document.querySelector ('phần tử của tôi');

  if (el.length) {
    // Làm gì đó với el
  } khác {
    setTimeout (pollDOM, 300); // thử lại sau 300 mili giây
  }
}

pollDOM ();
 

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

Nếu bạn muốn tìm hiểu thêm về phương pháp JavaScript setTimeout vui lòng tham khảo hướng dẫn của chúng tôi có nhiều ví dụ để giúp bạn tiếp tục.

Kiểm soát luồng trong JavaScript hiện đại

Thông thường khi viết JavaScript là chúng ta cần chờ điều gì đó xảy ra (ví dụ: dữ liệu được tìm nạp từ API), sau đó thực hiện phản hồi (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ờ đợi nhiều điều xảy ra, cú pháp sẽ nhanh chóng trở nên sởn gai ốc và bạn kết thúc trong địa ngục gọi lại.

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

Ví dụ: bằng cách sử dụng async, chúng tôi có thể viết lại mã ban đầu để lấy thông tin từ API GitHub:

  (không đồng bộ () => {
  const res = await fetch (`https: // api.github.com / users / jameshibbard`);
  const json = await res.json ();
  console.log (json.public_Vpose);
  console.log ("Xin chào!");
}) ();
 

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

Nếu đây là nhiều thứ 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 Điều khiển luồng trong Modern JS: Callbacks to Promise to Async / Await.

Đưa giấc ngủ vào JavaScript nguyên gốc

Nếu bạn vẫn còn ở bên tôi, thì tôi đoán bạn rất dễ thiết lập việc chặn luồng thực thi đó và làm cho JavaScript chờ nó ra.

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

  chức năng ngủ (mili giây) {
  const ngày = Date.now ();
  hãy để currentDate = null;
  làm {
    currentDate = Date.now ();
  } while (currentDate - ngày <mili giây);
}

console.log ("Xin chào");
ngủ (2000);
console.log ("Thế giới!");
 

Theo dự kiế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! Hồi

Nó hoạt động bằng cách sử dụng phương thức Date.now để lấy 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 số ngày . Sau đó, nó tạo ra một biến currentDate trống, trước khi vào một vòng làm ... trong khi . 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 currentDate đã khai báo trước đó. Vòng lặp sẽ tiếp tục trong khi chênh lệch giữa ngày currentDate nhỏ hơn độ trễ mong muốn tính bằng mili giây.

Công việc đã hoàn thành, phải không? Cũng không hoàn toàn đào

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 lưu ý, nó có một nhược điểm lớn: vòng lặp sẽ chặn luồng thực thi JavaScript 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 độ trễ lớn, thì có khả năng nó thậm chí có thể làm hỏng mọi thứ hoàn toàn.

Vậy phải làm sao?

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 ngủ ít xâm phạm hơn:

  chức năng ngủ (ms) {
  trả lại Promise mới (giải quyết => setTimeout (giải quyết, ms));
}

console.log ("Xin chào");
ngủ (2000) .then (() => {console.log ("Thế giới!");});
 

Mã này sẽ đăng nhập vào Hello Hello, chờ trong hai giây, sau đó đăng nhập Thế giới! Lát dưới mui xe chúng tôi đang sử dụng phương thức setTimeout để giải quyết một Promise sau một số mili giây nhất định.

Lưu ý rằng chúng ta cần sử dụng một cuộc gọi lại sau đó để đảm bảo tin nhắn thứ hai được ghi lại với độ trễ. Chúng tôi cũng có thể xâu chuỗi nhiều cuộc gọi lại vào lần đầu tiên:

  console.log ("Xin chào");
ngủ (2000)
  .then (() => {console.log ("Thế giới!");})
  .then (() => {
    ngủ (2000)
      .then (() => {console.log ("Tạm biệt!");})
    });
 

Điều này hoạt động, nhưng trông xấu xí. Chúng tôi có thể nâng cấp nó lên bằng cách sử dụng async ... đang chờ :

  chức năng ngủ (ms) {
  trả lại Promise mới (giải quyết => setTimeout (giải quyết, ms));
}

Hàm async delayGreet () {
  console.log ("Xin chào");
  Chờ ngủ (2000);
  console.log ("Thế giới!");
  Chờ ngủ (2000);
  console.log ("Tạm biệt!");
}

trì hoãnGreet ();
 

Cái này trông đẹp hơn, nhưng có nghĩa là bất kỳ mã nào đang sử dụng chức năng ngủ cần phải được đánh dấu là async .

   Xem Bút
yLLQJrX theo SitePoint (@SitePoint)
trên 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 thực hiện chứ không phải tạm dừng toàn bộ quá trình thực hiện chương trình. Chỉ có chức năng của bạn ngủ:

  chức năng ngủ (ms) {
  trả lại Promise mới (giải quyết => setTimeout (giải quyết, ms));
}

Hàm async delayGreet () {
  console.log ("Xin chào");
  Chờ ngủ (2000);
  console.log ("Thế giới!");
}

trì hoãnGreet ();
console.log ("Tạm biệt!");
 

Đoạn mã trên ghi lại như sau:

  Xin chào
Tạm biệt!
Thế giới!
 

Kết luận

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

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

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

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.

      

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

.
.
.
.