Phiên bản JavaScript của ngủ () là gì?


2335

Có cách nào tốt hơn để thiết kế một sleepJavaScript trong pausecomphàm hơn hàm sau ( được lấy từ đây ) không?

function pausecomp(millis)
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

Đây không phải là bản sao của Ngủ trong JavaScript - độ trễ giữa các hành động ; Tôi muốn có một giấc ngủ thực sự ở giữa một hàm và không bị trễ trước khi một đoạn mã được thực thi.


4
Sẽ được thiết lập vào giữa một thời gian, nếu tôi sử dụng setTimeout, thì trong khi đó, tôi sẽ tiếp tục xử lý và xếp hàng nhiều setTimeout cuối cùng sẽ chạy cùng lúc và tạo ra một chút đồng thời giữa chúng
fmsf

159
Đây là một giải pháp khủng khiếp - bạn sẽ nhai các chu trình xử lý trong khi không làm gì cả.
17 của 26

12
Mục đích duy nhất cho một giấc ngủ là bỏ phiếu hoặc chờ gọi lại - setInterval và setTimeout làm tốt hơn cả điều này.
annakata

1
Có lẽ bạn có thể làm những gì bạn muốn với kiểu chuyển tiếp trong JavaScript. Hãy xem bài viết này.
Ognyan Dimitrov

Câu trả lời:


2561

Cập nhật 2017 - 2019

Kể từ năm 2009 khi câu hỏi này được hỏi, JavaScript đã phát triển đáng kể. Tất cả các câu trả lời khác hiện đã lỗi thời hoặc quá phức tạp. Đây là cách thực hành tốt nhất hiện nay:

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

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two seconds later, showing sleep in a loop...');

  // Sleep in loop
  for (let i = 0; i < 5; i++) {
    if (i === 3)
      await sleep(2000);
    console.log(i);
  }
}

demo();

Đây là nó. await sleep(<duration>).

Hoặc như một lớp lót:

await new Promise(r => setTimeout(r, 2000));

Lưu ý rằng,

  1. awaitchỉ có thể được thực thi trong các chức năng có tiền tố với asynctừ khóa hoặc tại cấp cao nhất của tập lệnh của bạn trong một số môi trường (ví dụ: bảng điều khiển DevTools của Chrome hoặc Runkit).
  2. await chỉ tạm dừng hiện tại async chức năng

Hai tính năng JavaScript mới đã giúp viết chức năng "ngủ" này:

Khả năng tương thích

Nếu vì một lý do kỳ lạ nào đó, bạn đang sử dụng Node cũ hơn 7 (đã hết tuổi thọ ) hoặc đang nhắm mục tiêu các trình duyệt cũ, async/ awaitvẫn có thể được sử dụng qua Babel (một công cụ sẽ dịch mã JavaScript + các tính năng mới thành JavaScript cũ đơn giản) , với các transform-async-to-generatorplugin.


5
Công cụ tuyệt vời ở đây. Tôi tự hỏi, làm thế nào điều này ảnh hưởng hoặc liên quan đến các trạng thái "hoạt động" / "không hoạt động" của trình duyệt hiện đại sau khi JS gọi chế độ "ngủ"? Trình duyệt có thể chặn giấc ngủ như mong đợi đối với JS chung, để nhớ lại sau này khi trở thành "hoạt động" hay nó có hành vi khác không?
Andre Canilho

18
Hỗ trợ trình duyệt hiện tại cho việc này là gì? Tôi sẽ không coi các giải pháp trước đó là "lỗi thời" cho đến khi giải pháp này được hỗ trợ bởi đại đa số các trình duyệt hoặc ít nhất là tất cả các giải pháp phổ biến. Ngược lại, tôi sẽ xem xét giải pháp này thú vị nhưng không thể sử dụng / không thực tế cho đến khi nó có sự hỗ trợ rộng rãi.
Alvin Thompson

74
Đây không phải là "giấc ngủ thực sự" và không trả lời câu hỏi. Người hỏi đã phân biệt rõ ràng giữa stackoverflow.com/questions/758688/s ngủ-in-javascript và câu hỏi của anh ta. Trong giấc ngủ thực, không có mã nào khác có thể được thực thi (trừ khi trong luồng khác). Câu trả lời này là tốt cho câu hỏi khác.
niry

4
@jacroe - bộ chuyển mã xử lý các chức năng mũi tên cũng như async / await (điều này sẽ khiến IE nôn ra máu dù thế nào)
Jaromanda X

11
@niry JavaScript, là một ngôn ngữ đơn luồng, không phù hợp với giấc ngủ "thực", vì nó chạy trên cùng một luồng với giao diện người dùng và sẽ gây ra các trang web không phản hồi.
Patrick Roberts

849

(Xem câu trả lời cập nhật cho năm 2016 )

Tôi nghĩ rằng hoàn toàn hợp lý khi muốn thực hiện một hành động, chờ đợi, sau đó thực hiện một hành động khác. Nếu bạn đã quen viết bằng các ngôn ngữ đa luồng, có lẽ bạn có ý tưởng mang lại sự thực thi trong một khoảng thời gian cho đến khi luồng của bạn thức dậy.

Vấn đề ở đây là JavaScript là một mô hình dựa trên sự kiện đơn luồng. Mặc dù trong một trường hợp cụ thể, có thể sẽ rất tốt nếu toàn bộ động cơ chờ trong vài giây, nói chung đó là thực tế tồi. Giả sử tôi muốn sử dụng các chức năng của bạn trong khi viết của riêng tôi? Khi tôi gọi phương thức của bạn, tất cả các phương thức của tôi sẽ đóng băng. Nếu JavaScript bằng cách nào đó có thể bảo vệ bối cảnh thực thi chức năng của bạn, lưu trữ nó ở đâu đó, sau đó đưa nó trở lại và tiếp tục sau đó, thì giấc ngủ có thể xảy ra, nhưng về cơ bản đó sẽ là luồng.

Vì vậy, bạn gặp khá nhiều khó khăn với những gì người khác đã đề xuất - bạn sẽ cần chia mã của mình thành nhiều chức năng.

Câu hỏi của bạn là một chút lựa chọn sai, sau đó. Không có cách nào để ngủ theo cách bạn muốn, bạn cũng không nên theo đuổi giải pháp mà bạn đề xuất.


45
Đây không phải là một câu trả lời chính xác cả. Nếu Javascript không có chức năng ngủ, thì đó chỉ là do ECMAScript không yêu cầu. Đây là một lựa chọn thiết kế của cơ quan chịu trách nhiệm thiết kế Javascript. Nó có thể đã được thực hiện rằng thời gian chạy Javascript chờ một khoảng thời gian nhất định trước khi chạy dòng mã tiếp theo, nhưng nó đã được chọn không.
Didier A.

5
Một giấc ngủ có thể được thực hiện hoàn hảo trong JavaScript dù không phải với độ chính xác theo thời gian thực. Rốt cuộc nó là một hệ thống dựa trên sự kiện. Nếu các cuộc gọi async được hoàn thành, một sự kiện được kích hoạt. Tôi thấy không có lý do tại sao điều tương tự không thể xảy ra khi chế độ ngủ () được đưa ra sau khi điều khiển đó được đưa trở lại trình duyệt cho đến khi chế độ ngủ kết thúc, trả lại quyền điều khiển cho chức năng gọi. Và vâng, tôi cũng đồng ý rằng đôi khi ngủ rất tiện lợi, đặc biệt là khi các nhà phát triển TRƯỚC KHI bạn làm hỏng thiết kế đến mức BẠN không còn cách nào khác ngoài việc tái cấu trúc hoàn toàn mà bạn không có thời gian
Lawrence

Hãy thử Hypnotic, theo ý tưởng này: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat

4
Gọi javascript đơn luồng là một nhưng là một huyền thoại. Mặc dù nó có thể đúng về mặt kỹ thuật, về mặt chức năng, nó hoạt động như một ngôn ngữ đa luồng. Mô phỏng một ngã ba () rất dễ dàng và mặc dù năng suất () không thực sự có thể thực hiện được, bạn có thể tiến gần hơn bằng cách sử dụng bộ nhớ dùng chung để khóa / semaphore. Đối với các lập trình viên trung bình, nó có ý nghĩa để coi nó là đa luồng; tên kỹ thuật chỉ quan trọng đối với các nhà phát triển ngôn ngữ.
Benubird

8
Tôi đồng ý tại sao sleep()không thể có trong JS và hầu hết thời gian có nhiều cách tốt hơn để làm mọi việc. Nhưng tôi vẫn coi cách động cơ liên kết tất cả mọi thứ là một lỗ hổng thiết kế; không có lý do gì ngôn ngữ không thể có sleep()chức năng giới hạn trong một tập lệnh, trang hoặc chức năng cụ thể mà không có động cơ làm tắc nghẽn CPU và đóng băng ứng dụng như một kẻ điên. Đó là năm 2015 và bạn không nên đánh sập toàn bộ trình duyệt web while(1). Chúng tôi có Flash cho những thứ như thế.
Beejor

660

Trong JavaScript, tôi viết lại mọi chức năng để nó có thể kết thúc sớm nhất có thể. Bạn muốn trình duyệt trở lại quyền kiểm soát để nó có thể thực hiện thay đổi DOM của bạn.

Mỗi lần tôi muốn ngủ giữa chức năng của mình, tôi đã tái cấu trúc để sử dụng setTimeout() .

Biên tập

Giấc ngủ khét tiếng, hay trì hoãn, chức năng trong bất kỳ ngôn ngữ nào đang được tranh luận nhiều. Một số người sẽ nói rằng luôn phải có tín hiệu hoặc gọi lại để kích hoạt một chức năng nhất định, những người khác sẽ lập luận rằng đôi khi một khoảnh khắc trì hoãn tùy ý là hữu ích. Tôi nói điều đó với mỗi người và một quy tắc không bao giờ có thể ra lệnh bất cứ điều gì trong ngành này.

Viết một chức năng ngủ rất đơn giản và thậm chí còn có thể sử dụng nhiều hơn với JavaScript Promising:

// sleep time expects milliseconds
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});

190
Bằng cách đóng cửa. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
hỗn loạn

68
ok, và nếu mã không được sử dụng trong trang web thì sao?
Eugenio Miró

10
@ EugenioMiró nếu mã không được sử dụng trong trang web, hãy để mô hình đối tượng của máy chủ thực hiện phương thức ngủ. - Tôi nghĩ rằng câu hỏi hướng đến DOM được hiển thị với javascript chạy trên các trang web.
BrainSlugs83

31
@Nosredna vâng, chúng tôi hiểu cách thực hiện cuộc gọi không đồng bộ, điều này không giúp chúng tôi ngủ (). Tôi muốn các cuộc gọi của mình được thực hiện theo một thứ tự nhất định và để dữ liệu trở lại theo một thứ tự nhất định. Tôi có 5 cấp độ sâu trong một vòng lặp for. Tôi muốn thực hiện BLOCK. Một phương pháp ngủ thực sự sẽ không "làm chậm trình duyệt", tay ngủ điều khiển trở lại trình duyệt và bất kỳ luồng nào khác muốn có thời gian CPU trong khi nó vẫn đang chặn.
BrainSlugs83

382
đây không phải là một câu trả lời cho câu hỏi
TMS

303

Chỉ dành cho gỡ lỗi / dev , tôi đăng bài này nếu nó hữu ích cho ai đó

Điều thú vị, trong Fireorms (và có thể là các bảng điều khiển js khác), không có gì xảy ra sau khi nhấn enter, chỉ sau thời gian ngủ được chỉ định (...)

function sleepFor( sleepDuration ){
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ } 
}

Ví dụ sử dụng:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }

36
Đây không phải là một câu trả lời. Nó chính xác giống như mã trong câu hỏi, ngoại trừ ngắn hơn một chút.
jab

16
Bận rộn chờ đợi, thật sao? Trong JS? Trong vài giây? Nếu tôi bắt một trang web làm điều này, nó sẽ bị chặn.
mafu

34
@mafu Đó là lý do tại sao nó nói only for debug/dev... rolleyes
xDaizu

12
KHÔNG BAO GIỜ LÀM ĐIỀU NÀY. Điều này sẽ làm cho CPU đạt 100% trên lõi mà nó thực thi và sẽ chặn nó.
noego

3
Điều này rất hữu ích và có lẽ là cách DUY NHẤT để ngủ, trong ứng dụng javascript dòng lệnh, vì async / await không hữu ích.
Wheezil

177

Tôi đồng ý với các áp phích khác, một giấc ngủ bận rộn chỉ là một ý tưởng tồi.

Tuy nhiên, setTimeout không giữ thực thi, nó thực thi dòng tiếp theo của hàm ngay sau khi hết thời gian là SET, không phải sau khi hết thời gian, do đó không hoàn thành nhiệm vụ tương tự mà một giấc ngủ sẽ hoàn thành.

Cách để làm là phân tích chức năng của bạn trước và sau các bộ phận.

function doStuff()
{
  //do some things
  setTimeout(continueExecution, 10000) //wait ten seconds before continuing
}

function continueExecution()
{
   //finish doing things after the pause
}

Đảm bảo tên hàm của bạn vẫn mô tả chính xác những gì mỗi phần đang làm (IE GatherInputThenWait và CheckInput, thay vì funcPart1 và funcPart2)

Biên tập

Phương pháp này đạt được mục đích không thực thi các dòng mã bạn quyết định cho đến khi SAU thời gian chờ của bạn, trong khi vẫn trả lại quyền điều khiển cho PC khách để thực thi bất cứ điều gì khác mà nó đã xếp hàng.

Chỉnh sửa thêm

Như đã chỉ ra trong các ý kiến, điều này sẽ hoàn toàn KHÔNG LÀM VIỆC trong một vòng lặp. Bạn có thể thực hiện một số hack lạ mắt (xấu xí) để làm cho nó hoạt động theo vòng lặp, nhưng nói chung sẽ chỉ tạo ra mã spaghetti tai hại.


12
Vâng. Trường hợp điều này trở nên khó khăn là khi bạn có một vòng lặp, hoặc một vòng lặp lồng nhau. Bạn phải từ bỏ các vòng lặp của bạn và có quầy thay thế.
Nosredna

Touché. Ý tôi là, nó vẫn có thể, nhưng xấu xí và hackish trong trường hợp đó. Bạn cũng có thể sử dụng một số biến trạng thái boolean tĩnh, nhưng điều đó cũng khá hackish.
DevinB

2
-1 cho điều này. Một lần nữa, điều này không trả lời câu hỏi. Đây là câu trả lời nhiều hơn cho một câu hỏi như "Cách thực thi một chức năng không đồng bộ" khác rất nhiều so với "Cách chặn thực thi mã".
Deepak GM

6
@Nosredna Không, bạn sẽ sử dụng bao đóng. Ví dụ: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }for(var X = 0; X < 3;X++) { foo(X); }- giá trị của X được truyền vào foo, sau đó được sử dụng lại dưới tên indexkhi foo_continuecuối cùng được gọi.
Izkata

2
@Alexander Tất nhiên là có, vì quan điểm của setTimeout () là ngăn trình duyệt khóa bằng cách chạy mã không đồng bộ. Đặt console.log()bên trong foo_continue()trong phiên bản setTimeout và bạn sẽ nhận được kết quả tương tự.
Izkata

132

Vì tình yêu của $ DEITY, vui lòng không thực hiện chức năng ngủ chờ bận. setTimeoutsetIntervallàm mọi thứ bạn cần.

var showHide = document.getElementById('showHide');
setInterval(() => {
    showHide.style.visibility = "initial";
    setTimeout(() => {
        showHide.style.visibility = "hidden"
    }, 1000);
    ;
}, 2000);   
<div id="showHide">Hello! Goodbye!</div>

Cứ hai giây lại ẩn văn bản trong một giây. Điều này cho thấy cách sử dụng setInterval và setTimeout để hiển thị và ẩn văn bản mỗi giây.


3
Cũng không hoàn toàn mọi thứ: setInterval thực hiện ấn tượng tốt hơn về bỏ phiếu.
annakata

3
Điều gì sẽ không giữ lại đoạn mã trong công cụ JavaScript?
Deniz Dogan

10
Trừ khi bạn cần giấc ngủ được đồng bộ, trong trường hợp này đây là một câu hỏi hoàn toàn hợp lệ.
Aaron Dufour

36
Tôi nghĩ rằng nhiều người trong chúng ta có thể quên rằng JavaScript không phải là ngôn ngữ chỉ dành cho trình duyệt. Anh chàng này có thể đang tạo ra một tiện ích dòng lệnh Node yêu cầu tạm dừng ngắn mà không cần phải xử lý tất cả các vấn đề phạm vi biến đổi đi kèm với setTimeout.
Phil LaNasa

3
@PhilLaNasa: Nếu đóng cú pháp vẫn khiến người ta sợ hãi, người ta cần nghiêm túc khóa xuống và làm việc thông qua Node 101.
hỗn loạn

113

Tôi biết đây là một câu hỏi cũ, nhưng nếu (như tôi) bạn đang sử dụng Javascript với Rhino, bạn có thể sử dụng ...

try
{
  java.lang.Thread.sleep(timeInMilliseconds);
}
catch (e)
{
  /*
   * This will happen if the sleep is woken up - you might want to check
   * if enough time has passed and sleep again if not - depending on how
   * important the sleep time is to you.
   */
}

4
Đây có phải là một cuộc gọi đến Java?
Ken Sharp

14
Đây là Java không phải Javascript
RousseauAlexandre

18
@RousseauAlexandre Không chính xác. Đó là JavaScript sử dụng Rhino (vào thời điểm đó, nó cũng có thể là Nashorn những ngày này)
mjaggard

71

Nếu bạn đang sử dụng jQuery, một người nào đó thực sự đã tạo một plugin "trì hoãn" không gì khác hơn là một trình bao bọc cho setTimeout:

// Delay Plugin for jQuery
// - http://www.evanbot.com
// - © 2008 Evan Byrne

jQuery.fn.delay = function(time,func){
    this.each(function(){
        setTimeout(func,time);
    });

    return this;
};

Sau đó, bạn có thể sử dụng nó trong một hàng các lệnh gọi như mong đợi:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');

4
Đó không phải là một giải pháp tồi. Giữ bối cảnh và chuỗi.
Nosredna

39
Kể từ jQuery 1.4, .delay()là một phần của jQuery (mặc dù với ngữ nghĩa khác với cách triển khai ở trên). api.jquery.com/delay
Matt Ball

7
Điều mà câu hỏi này chắc chắn thiếu là một câu trả lời của jQuery . Rất vui vì chúng tôi đã nhận nó!
xDaizu

1
Nếu bạn cần một sự chậm trễ giữa hai cuộc gọi độc lập, có. Nếu bạn cần sự chậm trễ để làm chậm một vòng lặp, không.
WGroleau

46

Tôi cũng đã tìm kiếm giải pháp giấc ngủ (không phải mã sản xuất, chỉ dành cho dev / tests) và tìm thấy bài viết này:

http://narayanraman.blogspot.com/2005/12/javascript-s ngủ-or -wait.html

... Và đây là một liên kết khác với các giải pháp phía khách hàng: http://www.devcheater.com/

Ngoài ra, khi bạn đang gọi alert(), mã của bạn cũng sẽ bị tạm dừng, trong khi cảnh báo được hiển thị - cần tìm cách không hiển thị cảnh báo nhưng có được hiệu ứng tương tự. :)


35
Tôi đồng ý, rất nhiều người đang nói, "Không, đừng làm điều này trong mã sản xuất!" Vâng, tôi không muốn. Tôi muốn làm điều đó trong mã kiểm tra vứt đi, và kết quả là tôi không muốn dành nhiều thời gian để tạo ra một giải pháp thanh lịch.
user435779

31

Đây là một giải pháp đơn giản sử dụng XMLHttpRequest đồng bộ:

function sleep(n){
  var request = new XMLHttpRequest();
  request.open('GET', '/sleep.php?n=' + n, false);  // `false` makes the request synchronous
  request.send(null);
}

nội dung của ngủ.php:

<?php sleep($_GET['n']);

Bây giờ gọi nó với: ngủ (5);


5
@lukad, Sử dụng setTimeout()nếu điều đó hoạt động, nhưng nếu làm như vậy có nghĩa là làm sáng tỏ 1000 dòng gọi lại, điều này có thể bắt đầu không giống như một trò đùa.
pguardiario

11
Cách tiếp cận độc đáo, mặc dù không may, XMLHttpRequests không đồng bộ bị phản đối và sẽ bị xóa trong tương lai. Điều đó thật buồn cười, bởi vì thực tế đó là điều dẫn tôi đến câu hỏi này ngay từ đầu.
Beejor

Đây thực sự là một ý tưởng khá hay IMO. Mặc dù tôi không nghĩ API ngủ (URL yêu cầu) nên được công khai vì nó có thể bị lạm dụng.
Vahid Amiri

@Beejor luôn nghĩ về tương lai có nghĩa là sống dựa trên sự phi thực tế của tương lai :-)
user1742529

tốt nhưng bạn có biết nếu đôi khi internet chậm hoặc thời gian ping trang web cao hơn nó sẽ ngủ kịch bản nhiều hơn thời gian đối số. Giống như nếu bạn sử dụng sleep(300)và trang web mất 150 ms để phản hồi thì mã javascript sẽ ngủ trong 450ms. và nếu mất kết nối internet bởi trình duyệt, nó sẽ chỉ hoạt động trong 0ms. Vì vậy, nó không phải là giải pháp tốt hơn
H Chauhan

30

Bạn đi đây Như mã nói, đừng là một nhà phát triển tồi và sử dụng điều này trên các trang web. Đây là một chức năng tiện ích phát triển.

// Basic sleep function based on ms.
// DO NOT USE ON PUBLIC FACING WEBSITES.
function sleep(ms) {
    var unixtime_ms = new Date().getTime();
    while(new Date().getTime() < unixtime_ms + ms) {}
}

17
Điều đó về cơ bản giống như OP đã có.
Andrew Barber

5
Nói chính xác hơn, đó là những gì OP yêu cầu THAY ĐỔI.
WGroleau

Giải pháp này không tốt, nhưng ở một số nơi, async/awaitnó không đáp ứng một cách đáng tiếc, và chúng tôi phải sử dụng nó một cách bắt buộc.
Nabi KAZ

21

Cá nhân tôi thích sự đơn giản:

function sleep(seconds){
    var waitUntil = new Date().getTime() + seconds*1000;
    while(new Date().getTime() < waitUntil) true;
}

sau đó:

sleep(2); // Sleeps for 2 seconds

Tôi đang sử dụng tất cả thời gian để tạo thời gian tải giả trong khi tạo tập lệnh trong P5js


3
Tôi thấy đây là phiên bản tối ưu nhất của câu hỏi chính: nó không thực hiện bất kỳ phép toán nào trong vòng lặp, chỉ là một so sánh đơn giản. Hơi khó đọc tho.
bá chủ

4
KHÔNG BAO GIỜ LÀM ĐƯỢC. Bạn đã kiểm tra việc sử dụng CPU trong khi chức năng này đang hoạt động chưa? Nó sẽ gần 100% nếu bạn dành đủ thời gian cho nó.
noego

2
@hegez: Cho rằng vòng lặp sẽ chạy trong một khoảng thời gian đồng hồ treo tường cố định bất kể điều gì, có vẻ như tối ưu hóa vòng lặp là loại bên cạnh điểm.
ShadowRanger

@noego Làm sao vậy? Tôi mới thử nghiệm ở Nút 10, tôi hoàn toàn không có thay đổi sử dụng CPU
melMass

@melMass Chức năng này chỉ chặn luồng Node trong n giây bằng cách giữ CPU bận 100%. "Giải pháp" này là một ý tưởng cực kỳ tồi tệ vì hai lý do đó (chặn + sát thủ CPU). Chờ đợi đã không bị chặn, do đó không đồng bộ.
Jeremy Thille

20

Đầu tiên:

Xác định một chức năng bạn muốn thực hiện như thế này:

function alertWorld(){
  alert("Hello World");
}

Sau đó lên lịch thực hiện với phương thức setTimeout:

setTimeout(alertWorld,1000)

Lưu ý hai điều

  • đối số thứ hai là thời gian tính bằng milisecond
  • như một đối số đầu tiên, bạn phải truyền tên (tham chiếu) của hàm mà không có dấu ngoặc đơn


18

Giải pháp tốt hơn để khiến mọi thứ trông giống như những gì hầu hết mọi người muốn là sử dụng chức năng ẩn danh:

alert('start');
var a = 'foo';
//lots of code
setTimeout(function(){  //Beginning of code that should run AFTER the timeout
    alert(a);
    //lots more code
},5000);  // put the timeout here

Đây có lẽ là thứ gần nhất bạn sẽ có được thứ gì đó đơn giản là làm những gì bạn muốn.

Lưu ý, nếu bạn cần nhiều giấc ngủ, điều này có thể trở nên xấu xí khi vội vàng và bạn thực sự có thể cần phải suy nghĩ lại về thiết kế của mình.


đây là cái phù hợp với tôi trên trình duyệt máy tính để bàn và điện thoại di động cũ. Những người khác tôi đã cố gắng không làm việc trên tất cả.
Mike

10

Đối với các trình duyệt, tôi đồng ý rằng setTimeout và setInterval là cách tốt nhất.

Nhưng đối với mã phía máy chủ, nó có thể yêu cầu chức năng chặn (ví dụ: để bạn có thể thực hiện đồng bộ hóa luồng một cách hiệu quả).

Nếu bạn đang sử dụng node.js và sao băng, bạn có thể gặp phải những hạn chế khi sử dụng setTimeout trong một sợi. Đây là mã cho giấc ngủ phía máy chủ.

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

Xem: https://github.com/laverdet/node-fibers#s ngủ


Server may require a blocking function... Tôi không thấy việc chặn luồng chỉ của Node mạnh mẽ như thế nào và khiến toàn bộ máy chủ của bạn không phản hồi trong vài giây là một ý tưởng hay, nhưng dù sao đi nữa
Jeremy Thille

10

Tôi sẽ gói gọn setTimeOut trong Promise về tính nhất quán của mã với các tác vụ không đồng bộ khác: Demo trong Fiddle

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

Được sử dụng như thế:

sleep(2000).then(function() { 
   // Do something
});

Thật dễ nhớ cú pháp nếu bạn đã từng sử dụng Promise.


4
Tại sao điều này tốt hơn là chỉ sử dụng setTimeout (function () {/ * làm gì đó * /}, 2000);?
JSideris

10

Cập nhật 2019 bằng cách sử dụng Atomics.wait

Nên làm việc trong Node 9.3 trở lên.

Tôi cần một bộ đếm thời gian khá chính xác trong Node.js và nó hoạt động rất tốt cho điều đó. Tuy nhiên, có vẻ như có sự hỗ trợ cực kỳ hạn chế trong các trình duyệt.

let ms = 10000;
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);

Chạy một vài điểm chuẩn hẹn giờ 10 giây.

Với setTimeout, tôi gặp lỗi lên tới 7000 micro giây. (7ms)

Với Atomics, lỗi của tôi dường như ở dưới 600 micro giây. (0,6ms)

Cập nhật 2020: Tóm tắt

function sleep(millis){ // need help of a server-side page
  let netMillis=Math.max(millis-5,0); //assuming 5ms overhead
  let xhr=new XMLHttpRequest();
  xhr.open('GET','/sleep.jsp?millis='+netMillis+'&rand='+Math.random(), false);
  try{
    xhr.send();
  }catch(e){
  }
}
function sleepAsync(millis){ // use only in async function
  let netMillis=Math.max(millis-1,0); // assuming 1ms overhead
  return new Promise((resolve)=>{
    setTimeout(resolve, netMillis);
  });
}
function sleepSync(millis){ // use only in worker thread, currently Chrome-only
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, millis);
}

function sleepTest(){
  console.time('sleep');
  sleep(1000);
  console.timeEnd('sleep');
}
async function sleepAsyncTest(){
  console.time('sleepAsync');
  await sleepAsync(1000);
  console.timeEnd('sleepAsync');
}
function sleepSyncTest(){ 
  let source=`${sleepSync.toString()}
    console.time('sleepSync');
    sleepSync(1000);
    console.timeEnd('sleepSync');`;
  let src='data:text/javascript,'+encodeURIComponent(source);
  console.log(src);
  var worker=new Worker(src);
}

trong đó trang một server-side, ví dụ như sleep.jsp, vẻ thích

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>

Theo ý kiến ​​của tôi tốt hơn giải pháp được chấp nhận, không thể thực hiện như một chức năng đơn giản mà không có sự đồng bộ / chờ đợi trong người gọi.
GroovyDotCom

vâng, miễn là bạn biết rằng điều này đang chặn và điều đó thường không phải là một điều tốt
Kaccotanhook

Khá tuyệt, nhưng thực tế là điều này chỉ thực sự được hỗ trợ trong Chrome và Firefox không làm cho nó rất khả thi để sử dụng trên web. (Tháng 11 năm 2019)
JGreatorex

9

Hầu hết các câu trả lời ở đây là sai lầm hoặc ít nhất là lỗi thời. Không có lý do gì javascript phải được phân luồng đơn, và thực sự nó không phải vậy. Ngày nay, tất cả các trình duyệt chính đều hỗ trợ nhân viên, trước đây là trường hợp các thời gian chạy javascript khác như Rhino và Node.js hỗ trợ đa luồng.

'Javascript là một luồng' không phải là một câu trả lời hợp lệ. Ví dụ, chạy một chức năng ngủ trong một công nhân sẽ không chặn bất kỳ mã nào đang chạy trong luồng ui.

Trong thời gian chạy mới hơn hỗ trợ máy phát điện và năng suất, người ta có thể mang chức năng tương tự cho chức năng ngủ trong một môi trường luồng đơn:

// This is based on the latest ES6 drafts.
// js 1.7+ (SpiderMonkey/Firefox 2+) syntax is slightly different

// run code you want to sleep here (ommit star if using js 1.7)
function* main(){
    for (var i = 0; i < 10; i++) {
        // to sleep for 10 milliseconds 10 times in a row
        yield 10;
    }

    yield 5;
    console.log('I just slept 5 milliseconds!');
}

// resume the given generator after ms milliseconds
function resume(ms, generator){
    setTimeout(function(){
        // ommit .value if using js 1.7
        var nextSleep = generator.next().value;
        resume(nextSleep, generator);
    }, ms);
}

// initialize generator and get first sleep for recursive function
var
    generator = main(),
    firstSleep = generator.next().value;

// initialize recursive resume function
resume(firstSleep, generator);

Việc bắt chước giấc ngủ này khác với chức năng ngủ thực sự vì nó không chặn luồng. Nó chỉ đơn giản là đường trên đầu chức năng setTimeout hiện tại của javascript. Loại chức năng này đã được triển khai trong Task.js và sẽ hoạt động ngay hôm nay trong Firefox.


Công nhân không được triển khai trong IE, ít nhất là qua phiên bản 10. Hiện tại đại diện cho một lượng lớn người dùng.
Beejor

Đúng, và thậm chí sau đó không thực tế khi sleepsử dụng nhiều công nhân. Nếu sử dụng các hàm tạo Node.js đã được triển khai và có thể được sử dụng như mô tả. Các trình duyệt chính không có tất cả các trình tạo được thực hiện như ngày nay.
Gabriel Ratener

8

Tôi đã tìm kiếm / googled khá nhiều trang web trên javascript ngủ / chờ ... và KHÔNG có câu trả lời nào nếu bạn muốn javascript thành "CHẠY, TRÌ HOÃN, CHẠY" ... những gì hầu hết mọi người nhận được là "RUN, RUN (vô dụng thứ), CHẠY "hoặc" CHẠY, CHẠY + CHẠY chậm trễ "....

Vì vậy, tôi đã ăn một số bánh mì kẹp thịt và suy nghĩ ::: đây là một giải pháp hiệu quả ... nhưng bạn phải cắt mã chạy của mình ... ::: vâng, tôi biết, đây chỉ là một cách dễ dàng hơn để đọc tái cấu trúc .. . vẫn...

//......................................... //ví dụ 1:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setInterval
var i = 0;

function run() {
    //pieces of codes to run
    if (i==0){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==1){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i >2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" is ran</p>"; }
    if (i==5){document.getElementById("id1").innerHTML= "<p>all code segment finished running</p>"; clearInterval(t); } //end interval, stops run
    i++; //segment of code finished running, next...
}

run();
t=setInterval("run()",1000);

</script>
</body>
</html>

// .................................... // example2:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout
var i = 0;

function run() {
    //pieces of codes to run, can use switch statement
    if (i==0){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(1000);}
    if (i==1){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(2000);}
    if (i==2){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>"; sleep(3000);}
    if (i==3){document.getElementById("id1").innerHTML= "<p>code segment "+ i +" ran</p>";} //stops automatically
    i++;
}

function sleep(dur) {t=setTimeout("run()",dur);} //starts flow control again after dur

run(); //starts
</script>
</body>
</html>

// ................. ví dụ3:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout
var i = 0;

function flow() {
    run(i);
    i++; //code segment finished running, increment i; can put elsewhere
    sleep(1000);
    if (i==5) {clearTimeout(t);} //stops flow, must be after sleep()
}

function run(segment) {
    //pieces of codes to run, can use switch statement
    if (segment==0){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==1){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
}

function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

flow(); //starts flow
</script>
</body>
</html>

// .............. ví dụ4:

<html>
<body>
<div id="id1">DISPLAY</div>

<script>
//javascript sleep by "therealdealsince1982"; copyrighted 2009
//setTimeout, switch
var i = 0;

function flow() {
    switch(i)
    {
        case 0:
            run(i);
            sleep(1000);
            break;
        case 1:
            run(i);
            sleep(2000);
            break;
        case 5:
            run(i);
            clearTimeout(t); //stops flow
            break;
        default:
            run(i);
            sleep(3000);
            break;
    }
}

function run(segment) {
    //pieces of codes to run, can use switch statement
    if (segment==0){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==1){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment==2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    if (segment >2){document.getElementById("id1").innerHTML= "<p>code segment "+ segment +" is ran</p>"; }
    i++; //current segment of code finished running, next...
}

function sleep(dur) {t=setTimeout("flow()",dur);} //starts flow control again after dur

flow(); //starts flow control for first time...
</script>
</body>
</html>

5
Ok, điều này hoạt động với setTimeput, nhưng thật khó để biết điều gì đang xảy ra. Sử dụng setTimeout chính nó dễ dàng hơn thế này.
khai mạc

7
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

Nó giống như câu hỏi thực sự. Không có nhiều điểm làm cho nó là câu trả lời thực sự.
EML

2
Không phải là một giải pháp tốt - sử dụng điều này trong JavaScriptExecutor của Selenium đã treo trình duyệt Chrome của tôi khoảng 50% thời gian trên MacBook Pro 2104.
emery

7

Giải pháp ngắn nhất mà không có bất kỳ sự phụ thuộc nào:

await new Promise(resolve => setTimeout(resolve, 5000));

Nó không hoạt động trong IE11. Chúng tôi nhận được lỗi cú pháp cho chức năng mũi tên.
DDphp

@ Java-DK sử dụngawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a

6

Bạn không thể thực hiện một giấc ngủ như thế trong JavaScript, hay nói đúng hơn là bạn không nên. Chạy một giấc ngủ hoặc một vòng lặp while sẽ khiến trình duyệt của người dùng bị treo cho đến khi hoàn thành vòng lặp.

Sử dụng bộ hẹn giờ, như được chỉ định trong liên kết bạn đã tham chiếu.


6

Một tình huống trong đó bạn có thể muốn có chức năng ngủ () thay vì sử dụng setTimeout () là nếu bạn có chức năng phản hồi lại lần nhấp của người dùng, cuối cùng sẽ mở một cửa sổ bật lên tức là mới và bạn đã bắt đầu một số xử lý yêu cầu một khoảng thời gian ngắn để hoàn thành trước khi cửa sổ bật lên được hiển thị. Di chuyển cửa sổ đang mở thành một đóng có nghĩa là nó thường bị trình duyệt chặn.


6

Tôi có thể hiểu mục đích của chức năng ngủ nếu bạn phải xử lý thực thi đồng bộ. Các hàm setInterval và setTimeout tạo ra một luồng thực thi song song trả lại chuỗi thực hiện trở lại chương trình chính, điều này không hiệu quả nếu bạn phải chờ một kết quả nhất định. Tất nhiên người ta có thể sử dụng các sự kiện và xử lý, nhưng trong một số trường hợp không phải là mục đích.


6

Thêm hai bit của tôi. Tôi cần một sự bận rộn - chờ đợi cho mục đích thử nghiệm. Tôi không muốn chia mã vì đó sẽ là rất nhiều công việc, vì vậy đơn giản là đã làm điều đó cho tôi.

for (var i=0;i<1000000;i++){                    
     //waiting
  }

Tôi không thấy bất kỳ nhược điểm nào trong việc này và nó đã giúp tôi rất nhiều.


Điều đó có thể được biên soạn đi.
Viktor Sehr

Xin đừng làm theo cách này. Đây là một cuộc gọi ngủ chặn , điều đó có nghĩa là không có javascript nào khác có thể chạy trong khi mã của bạn đang ăn cắp chuỗi JS.
Steve Midgley

5
@SteveUngley "không có javascript nào khác [có thể] chạy trong khi mã của bạn đang ăn cắp chủ đề JS" dường như chính xác là những gì OP muốn làm ¯_ () _ /
drigoangelo

1
Tôi vừa chạy một số thử nghiệm và nó xuất hiện ngay cả một vòng lặp trống sẽ chặn trình duyệt và CPU (không chỉ JavaScript). Và việc sử dụng forcác vòng lặp sẽ luôn luôn thực thi ngay lập tức, bất kể giá trị tối đa là bao nhiêu ivà ngay cả với mã toán học phức tạp được đặt bên trong. Vì vậy, trừ khi bạn chỉ chờ vài mili giây, dường như vẫn không có cách nào để ngủ một cách duyên dáng trong JS.
Beejor

1 triệu là quá lớn. Đối với tôi đủ 10k
Vlad

6

Nó có thể được thực hiện bằng phương thức ngủ của Java. Tôi đã thử nghiệm nó trong FF và IE và nó không khóa máy tính, nhai tài nguyên hoặc gây ra các cú đánh máy chủ vô tận. Có vẻ như một giải pháp sạch cho tôi.

Trước tiên, bạn phải tải Java lên trang và cung cấp các phương thức của nó. Để làm điều đó, tôi đã làm điều này:

<html>
<head>

<script type="text/javascript">

  function load() {
    var appletRef = document.getElementById("app");
    window.java = appletRef.Packages.java;
  } // endfunction

</script>

<body onLoad="load()">

<embed id="app" code="java.applet.Applet" type="application/x-java-applet" MAYSCRIPT="true" width="0" height="0" />

Sau đó, tất cả những gì bạn phải làm khi bạn muốn tạm dừng không đau trong JS của mình là:

java.lang.Thread.sleep(xxx)

Trong đó xxx là thời gian tính bằng mili giây. Trong trường hợp của tôi (bằng cách biện minh), đây là một phần của việc thực hiện đơn hàng phụ trợ tại một công ty rất nhỏ và tôi cần in một hóa đơn phải được tải từ máy chủ. Tôi đã làm điều đó bằng cách tải hóa đơn (dưới dạng trang web) vào iFrame và sau đó in iFrame. Tất nhiên, tôi phải đợi cho đến khi trang được tải đầy đủ trước khi tôi có thể in, do đó, JS phải tạm dừng. Tôi đã thực hiện điều này bằng cách yêu cầu trang hóa đơn (trong iFrame) thay đổi trường biểu mẫu ẩn trên trang mẹ với sự kiện onLoad. Và mã trên trang mẹ để in hóa đơn trông như thế này (phần không liên quan được cắt cho rõ ràng):

var isReady = eval('document.batchForm.ready');
isReady.value=0;

frames['rpc_frame'].location.href=url;

while (isReady.value==0) {
  java.lang.Thread.sleep(250);
} // endwhile

window.frames['rpc_frame'].focus();
window.frames['rpc_frame'].print();

Vì vậy, người dùng nhấn nút, tập lệnh tải trang hóa đơn, sau đó chờ, kiểm tra mỗi quý một lần để xem trang hóa đơn đã tải xong chưa, sau đó bật hộp thoại in để người dùng gửi nó đến máy in. QED.


12
Có vẻ tâm hồn khá quái dị khi xem xét điều đơn giản mà tác giả muốn đạt được.
xaralis

2
Điều này phụ thuộc vào các Applet Java không được dùng nữa.
Vahid Amiri

6

Rất nhiều câu trả lời không (trực tiếp) trả lời câu hỏi, và câu trả lời này cũng không ...

Đây là hai xu của tôi (hoặc chức năng):

Nếu bạn muốn các hàm ít cồng kềnh hơn setTimeoutsetInterval, bạn có thể bọc chúng trong các hàm chỉ đảo ngược thứ tự của các đối số và đặt cho chúng các tên hay:

function after(ms, fn){ setTimeout(fn, ms); }
function every(ms, fn){ setInterval(fn, ms); }

Phiên bản CoffeeScript:

after = (ms, fn)-> setTimeout fn, ms
every = (ms, fn)-> setInterval fn, ms

Sau đó, bạn có thể sử dụng chúng độc đáo với các chức năng ẩn danh:

after(1000, function(){
    console.log("it's been a second");
    after(1000, function(){
        console.log("it's been another second");
    });
});

Bây giờ nó đọc dễ dàng là "sau N mili giây, ..." (hoặc "mỗi N mili giây, ...")


5

Đối với trường hợp cụ thể muốn loại bỏ một tập hợp các cuộc gọi được thực hiện bởi một vòng lặp, bạn có thể sử dụng một cái gì đó giống như mã dưới đây với nguyên mẫu. Nếu không có nguyên mẫu, bạn có thể thay thế chức năng trì hoãn bằng setTimeout.

function itemHandler(item)
{
    alert(item);
}

var itemSet = ['a','b','c'];

// Each call to itemHandler will execute
// 1 second apart
for(var i=0; i<itemSet.length; i++)
{
    var secondsUntilExecution = i;
    itemHandler.delay(secondsUntilExecution, item)
}

5

Nếu bạn đang sử dụng node.js, bạn có thể xem các sợi - phần mở rộng C gốc cho nút, một mô phỏng đa luồng.

Nó cho phép bạn làm thật sleep theo cách ngăn chặn sự thực thi trong một sợi, nhưng nó không chặn trong luồng chính và các sợi khác.

Đây là một ví dụ mới từ readme của riêng họ:

// sleep.js

var Fiber = require('fibers');

function sleep(ms) {
    var fiber = Fiber.current;
    setTimeout(function() {
        fiber.run();
    }, ms);
    Fiber.yield();
}

Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

- và kết quả là:

$ node sleep.js
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.