Câu hỏi Phiên bản JavaScript của giấc ngủ () là gì?


Có cách nào tốt hơn để thiết kế một sleep trong JavaScript so với những điều sau pausecomp chức năng (lấy từ đây)?

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 - chậm trễ giữa các hành động; tôi muốn một ngủ thật ở giữa một hàm, và không phải là một sự chậm trễ trước khi một đoạn mã thực thi.


1527
2017-10-07 09:44


gốc


Đó là để thiết lập ở giữa một thời gian, nếu tôi sử dụng setTimeout trong khi sẽ tiếp tục xử lý và xếp hàng setTimeouts nhiều hơn mà cuối cùng sẽ được chạy cùng một lúc và làm cho một chút đồng thời giữa mình - fmsf
Đây là một giải pháp khủng khiếp - bạn sẽ nhai chu trình xử lý trong khi không làm gì cả. - 17 of 26
Mục đích duy nhất cho một giấc ngủ là bỏ phiếu hoặc chờ đợi một cuộc gọi lại - setInterval và setTimeout làm tốt hơn cả điều này. - annakata
Có lẽ bạn có thể làm những gì bạn muốn với phong cách tiếp tục đi qua trong JavaScript. Hãy xem bài viết này. - Ognyan Dimitrov


Các câu trả lời:


Bản cập nhật năm 2017

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à thực hành tốt nhất hiện tại:

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

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two second later');
}

demo();

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

Bạn có thể thử mã này trực tiếp trên Runkit. Lưu ý rằng,

  1. await chỉ có thể được thực thi trong các hàm được bắt đầu bằng async từ khóa. Runkit kết thúc tốt đẹp mã của bạn trong một hàm async trước khi thực hiện nó.
  2. await chỉ tạm dừng dòng điện async chức năng

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

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

Nếu vì lý do nào đó bạn đang sử dụng Node lớn hơn 7 hoặc đang nhắm mục tiêu các trình duyệt cũ, async/await vẫn có thể được sử dụng thông qua Babel (một công cụ sẽ transpile JavaScript + các tính năng mới vào JavaScript cũ thuần túy), với transform-async-to-generator cắm vào. Chạy

npm install babel-cli --save

Tạo nên .babelrc với:

{
  "plugins": [
    "transform-async-to-generator",
  ]
}

Sau đó chạy mã của bạn với

node_modules/babel-cli/bin/babel-node.js sleep.js

Nhưng một lần nữa, bạn không cần điều này nếu bạn đang sử dụng Node 7 hoặc mới hơn, hoặc nếu bạn đang nhắm mục tiêu các trình duyệt hiện đại.


1089



Những thứ tuyệt vời ở đây. Tôi tự hỏi, điều này ảnh hưởng như thế nào 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 cho JS chung hay không, để gọi lại sau khi trở thành "hoạt động", hoặc nó có một hành vi khác không? - Andre Canilho
Trình duyệt hiện tại hỗ trợ cho điều này là gì? Tôi sẽ không xem xét 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 phần lớn các trình duyệt, hoặc ít nhất là tất cả các trình duyệt thông dụng. Ngược lại, tôi sẽ xem xét giải pháp này thú vị nhưng không sử dụng được / không thực tế cho đến khi nó có sự hỗ trợ rộng rãi. - Alvin Thompson
@AlvinThompson: phần lớn các phát triển web hiện đại sử dụng các trình chuyển đổi, do đó, các trình duyệt hỗ trợ trình duyệt có vấn đề nhỏ hơn mã trình duyệt sạch hơn và tương lai hơn. Dù sao, hãy xem caniuse. - Dan Dascalescu
Đây không phải là "giấc ngủ thực" và không trả lời câu hỏi. Người được hỏi đã phân biệt rõ ràng giữa stackoverflow.com/questions/758688/sleep-in-javascript và câu hỏi của anh ta. Trong giấc ngủ thực sự không có mã nào khác có thể được thực hiện (trừ khi trong các chủ đề khác). Câu trả lời này là tốt cho câu hỏi khác. - niry
@jacroe - trình điều khiển transpiler 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 bị nôn ra máu) - Jaromanda X


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

Tôi nghĩ 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 với việc viết bằng các ngôn ngữ đa luồng, bạn có thể có ý tưởng về thực thi trong một khoảng thời gian nhất định cho đến khi luồng của bạn được đánh thức.

Vấn đề ở đây là JavaScript là một mô hình dựa trên sự kiện đơn luồng. Trong khi trong một trường hợp cụ thể, nó có thể là tốt đẹp để có toàn bộ động cơ chờ đợi cho một vài giây, nói chung nó là thực hành xấu. 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 pháp của bạn, phương pháp của tôi sẽ bị đóng băng. Nếu JavaScript bằng cách nào đó có thể bảo vệ ngữ cảnh thực thi của chức năng của bạn, lưu trữ nó ở đâu đó, sau đó mang nó trở lại và tiếp tục sau đó, sau đó giấc ngủ có thể xảy ra, nhưng về cơ bản sẽ là luồng.

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

Câu hỏi của bạn là một chút của một sự 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 đề nghị.


830



Đây không phải là câu trả lời đúng. Nếu Javascript không có chức năng ngủ, chỉ vì ECMAScript không yêu cầu nó. Nó là một sự lựa chọn thiết kế của cơ thể chịu trách nhiệm về thiết kế của Javascript. Nó có thể đã được thực hiện rằng thời gian chạy Javascript chờ đợi một lượ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.
Một giấc ngủ có thể được thực hiện hoàn hảo trong JavaScript mặc dù không phải với độ chính xác thời gian thực. Sau khi tất cả nó là một sự kiện dựa trên hệ thống. Nếu cuộc gọi không đồng bộ được hoàn thành, sự kiện sẽ được kích hoạt. Tôi thấy không có lý do tại sao cùng không thể có được khi một giấc ngủ () được ban hành sau khi kiểm soát được trả lại cho trình duyệt cho đến khi ngủ kết thúc, trở về kiểm soát chức năng gọi. Và có, tôi cũng đồng ý rằng đôi khi ngủ có ích đặc biệt là khi các nhà phát triển TRƯỚC KHI bạn vặn thiết kế quá tệ đế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
Gọi javascript đơn luồng là một huyền thoại. Mặc dù nó có thể đúng về mặt kỹ thuật, nhưng nó hoạt động giống như một ngôn ngữ đa luồng. Mô phỏng một ngã ba () là dễ dàng một cách dễ dàng, và mặc dù yield () không thực sự khả thi, nhưng bạn có thể sử dụng bộ nhớ chia sẻ để khóa / semaphore. Đối với các lập trình viên trung bình, nó có ý nghĩa để xử lý nó như đa luồng; tên kỹ thuật chỉ quan trọng đối với nhà phát triển ngôn ngữ. - Benubird
Tôi đồng ý vì sao sleep() là không thể trong JS, và hầu hết thời gian có những cách tốt hơn để làm việc. Nhưng tôi vẫn xem xét cách động cơ liên kết tất cả mọi thứ để trở thành 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ơ clobbering CPU và đóng băng ứng dụng như một maniac. Đó là năm 2015 và bạn không thể làm hỏng toàn bộ trình duyệt web bằng while(1). Chúng tôi có Flash cho những thứ như thế. - Beejor


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

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

Tôi sẽ chỉnh sửa câu trả lời này vì tôi thấy điều này hữu ích:

Giấc ngủ khét tiếng, hoặc trì hoãn, chức năng trong bất kỳ ngôn ngữ nào được tranh luận nhiều. Một số người sẽ nói rằng luôn luôn có một 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 thời điểm trì hoãn tùy ý là hữu ích. Tôi nói rằng với mỗi chính họ và một quy tắc không bao giờ có thể ra lệnh cho bất cứ điều gì trong ngành công nghiệp này.

Viết chức năng ngủ đơn giản và thậm chí còn hữu dụng hơn với JavaScript Promises:

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

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

590



Bằng cách đóng cửa. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); } - chaos
ok, và điều gì sẽ xảy ra nếu mã không được sử dụng trong một trang web? - Eugenio Miró
@ EugenioMiró nếu mã không được dự định để được sử dụng trong một trang web, có mô hình đối tượng của máy chủ thực hiện một phương pháp ngủ. - Tôi nghĩ rằng câu hỏi được hướng tới DOM được tiếp xúc với javascript chạy trên các trang web. - BrainSlugs83
@Nosredna có, 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 tôi được thực hiện theo một thứ tự nhất định và để dữ liệu được trả lại theo một thứ tự nhất định. Tôi là 5 cấp độ sâu trong vòng lặp for. Tôi muốn BLOCK thực hiện. Một phương pháp ngủ thực sự sẽ không "làm chậm trình duyệt", tay ngủ kiểm soát trở lại trình duyệt và bất kỳ chủ đề nào khác muốn thời gian CPU trong khi nó vẫn đang chặn. - BrainSlugs83
đây không phải là câu trả lời cho câu hỏi. - TMS


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

Thú vị thứ, trong Firebug (và có lẽ khác js console), không có gì xảy ra sau khi nhấn enter, chỉ sau khi thời gian ngủ quy đị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 !"); }

269



Đây không phải là câu trả lời. Nó chính xác giống như mã trong câu hỏi, ngoại trừ hơi ngắn hơn. - jab
Bận rộn chờ đợi, thực sự? 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
@mafu Đó là lý do tại sao nó nói only for debug/dev... đảo mắt - xDaizu
@mafu đó là sự thật, nó rất khó khăn để đưa ra một ví dụ thích hợp mà nó có thể xứng đáng với câu hỏi của riêng mình! - xDaizu
KHÔNG BAO GIỜ LÀM NÀY. Điều này sẽ làm cho CPU đạt 100% trên lõi mà nó thực hiện và sẽ chặn nó. - noego


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 nắm 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 chờ SET, chứ không phải sau khi hết thời gian chờ, do đó không hoàn thành nhiệm vụ tương tự mà giấc ngủ sẽ thực hiện.

Cách để làm điều đó là để phân tích chức năng của bạn ở trước và sau các phần.

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

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

Hãy chắc chắn rằng tên hàm của bạn vẫn mô tả chính xác những gì từng phần đang làm (I.E. GatherInputThenWait và CheckInput, thay vì funcPart1 và funcPart2)

Chỉnh sửa 

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

Chỉnh sửa thêm

Như đã chỉ ra trong các ý kiến ​​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 (xấu xí) để làm cho nó hoạt động trong một vòng lặp, nhưng nói chung sẽ chỉ làm cho mã spaghetti tai hại.


164



Ừ. Trường hợp này được khôn lanh là khi bạn có một vòng lặp, hoặc một vòng lặp lồng nhau ngay cả. Bạn phải từ bỏ vòng lặp của bạn và có quầy thay thế. - Nosredna
Touché. Ý tôi là, nó vẫn sẽ có thể, nhưng xấu xí và bị hack 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á đáng sợ. - DevinB
-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à một câu trả lời cho một câu hỏi như "Cách thực hiện một hàm không đồng bộ" khác với "Cách chặn thực thi mã". - Deepak G M
@Nosredna Không, bạn sẽ sử dụng một đóng cửa. Ví dụ: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); } và for(var X = 0; X < 3;X++) { foo(X); } - các giá trị của X được chuyển vào foo, sau đó được sử dụng lại dưới tên index khi nào foo_continue cuối cùng được gọi. - Izkata
@Alexander Tất nhiên, vì điểm setTimeout () là ngăn chặn trình duyệt khóa bằng cách chạy mã không đồng bộ. Đặt console.log()phía trong foo_continue() trong phiên bản setTimeout và bạn nhận được kết quả tương tự. - Izkata


Đối với tình yêu của $ DEITY xin vui lòng không làm cho một chức năng ngủ chờ đợi bận rộn. setTimeout và setInterval làm mọi thứ bạn cần.


113



Tôi đồng ý. Sẽ không thực sự "ngủ" đóng băng lên toàn bộ động cơ javascript ... - Skurmedel
Cũng không hoàn toàn tất cả mọi thứ: setInterval thực hiện một ấn tượng tốt hơn nhiều về bỏ phiếu. - annakata
Đoạn mã đó là gì không phải giữ lại trong công cụ JavaScript? - Deniz Dogan
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
Tôi nghĩ 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. Dude này có thể đang tạo 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 xử lý tất cả các vấn đề phạm vi biến đi kèm với setTimeout. - Phil LaNasa


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.
   */
}

109



Đây có phải là một cuộc gọi đến Java không? - Ken Sharp
Có, một cuộc gọi đến giấc ngủ thread của Java. - mjaggard
Đây là Java không phải Javascript - RousseauAlexandre
@RousseauAlexandre Không chính xác. Nó là JavaScript sử dụng Rhino (vào thời điểm đó, nó có thể bằng Nashorn những ngày này) - mjaggard


Nếu bạn đang sử dụng jQuery, một người nào đó thực sự tạo ra một plugin "chậm trễ" đó là không có gì hơn một wrapper 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 cuộc gọi hàm như mong đợi:

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

65



Đó không phải là một giải pháp tồi. Giữ bối cảnh và khả năng gắn kết. - Nosredna
Kể từ jQuery 1.4, .delay() là một phần của jQuery (mặc dù có ngữ nghĩa khác với việc thực hiện ở trên). api.jquery.com/delay - Matt Ball
Câu hỏi này chắc chắn thiếu là một Câu trả lời jQuery. Rất vui vì chúng tôi đã có nó! - xDaizu
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


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

http://narayanraman.blogspot.com/2005/12/javascript-sleep-or-wait.html

... và đây là một liên kết khác với giải pháp phía máy khách: 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 phải tìm cách để không hiển thị cảnh báo nhưng có cùng tác dụng. :)


42



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!" Yeah, um, tôi không muốn. Tôi muốn làm điều đó trong mã thử nghiệm throwaway, và kết quả là tôi không muốn dành nhiều thời gian làm một giải pháp thanh lịch. - user435779
Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn nên đưa các phần quan trọng của câu trả lời vào đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. - - Từ đánh giá - Adelin


Đây rồi. Như mã nói, không phải là một dev xấu và sử dụng điều này trên các trang web. Đó 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) {}
}

28



Đó là cơ bản giống như OP đã có. - Andrew Barber
Để chính xác hơn, đó là những gì OP yêu cầu cho một ALTERNATIVE. - WGroleau
Giải pháp không tốt, nhưng ở một số nơi async/await nó không đáp ứng không may, và chúng ta phải sử dụng nó một cách bắt buộc. - Nabi K.A.Z.