Ngủ trong JavaScript - độ trễ giữa các hành động


129

Có cách nào tôi có thể ngủ trong JavaScript trước khi nó thực hiện một hành động khác không?

Thí dụ:

 var a = 1+3;
 // Sleep 3 seconds before the next action here
 var b = a + 4;

Câu trả lời:


140

Bạn có thể sử dụng setTimeoutđể đạt được hiệu quả tương tự:

var a = 1 + 3;
var b;
setTimeout(function() {
    b = a + 4;
}, (3 * 1000));

Điều này không thực sự 'ngủ' JavaScript, nó chỉ thực thi chức năng được truyền đến setTimeoutsau một khoảng thời gian nhất định (được chỉ định bằng mili giây). Mặc dù có thể viết hàm ngủ cho JavaScript, tốt nhất nên sử dụng setTimeoutnếu có thể vì nó không đóng băng mọi thứ trong suốt thời gian ngủ.


9
Cũng có một cái nhìn tại setInterval (). Nó tương tự như setTimeout (), nhưng chức năng của bạn được gọi nhiều lần (cho đến khi bạn dừng nó), rất hữu ích nếu bạn muốn làm gì đó trong khi ngủ (như thực hiện cập nhật tiến độ, giữ một số trạng thái nội bộ hoặc bất cứ điều gì).
Anders Sandvig

5
Điều này không trả lời câu hỏi. Câu hỏi yêu cầu tương đương với "giấc ngủ" mà điều này không có.
felwithe

Mặc dù câu trả lời này không khớp với những gì câu hỏi đã hỏi, nhưng nó hữu ích hơn vòng lặp và so sánh Date.now (). Không có gì để sử dụng một vòng lặp bị chặn trong giấc ngủ thực hiện.
Li Chunlin

2
Trừ khi, tất nhiên, một vòng lặp chặn chính xác là những gì ai đó muốn.
Wonko the Sane

55

Trong trường hợp bạn thực sự cần sleep()chỉ để kiểm tra một cái gì đó. Nhưng hãy lưu ý rằng nó sẽ bị sập trình duyệt hầu hết thời gian trong khi gỡ lỗi - có lẽ đó là lý do tại sao bạn cần nó. Trong chế độ sản xuất, tôi sẽ nhận xét chức năng này.

function pauseBrowser(millis) {
    var date = Date.now();
    var curDate = null;
    do {
        curDate = Date.now();
    } while (curDate-date < millis);
}

Không sử dụng new Date()trong vòng lặp, trừ khi bạn muốn lãng phí bộ nhớ, năng lượng xử lý, pin và có thể là tuổi thọ của thiết bị.


8
Câu trả lời này xứng đáng được nhiều phiếu hơn. Diễn viên chính câu hỏi chỉ là nguyên nhân của câu trả lời này.
jagc

Điều gì về cảnh báo "quá nhiều đệ quy"?
Oki Erie Rinaldi

1
@OkiErieRinaldi Không có đệ quy ở đó, nó chỉ là một vòng lặp.
Rodrigo

7
@ 3.1415926535897932384626433833 Chà, ai đó đã yêu cầu chức năng "ngủ", đó là những gì ở đây. Tôi đã sử dụng nó một lần, không thể nhớ chính xác loại gỡ lỗi nào. Nếu tôi cần nó một lần nữa, tôi biết chính xác nơi để tìm thấy nó. Nếu bạn thích chức năng khác, đó là lựa chọn của bạn. Thật tuyệt vời khi có thể lựa chọn?
Rodrigo

2
"Chờ đợi bận rộn".
Zeek2

13

Phiên bản ECMAScript 6, sử dụng các trình tạo có năng suất để "chặn mã":

Bởi vì câu hỏi ban đầu đã được đăng bảy năm trước, tôi không buồn trả lời với mã chính xác, bởi vì nó quá dễ và đã được trả lời. Điều này sẽ giúp trong các vấn đề phức tạp hơn, như nếu bạn cần ít nhất hai giấc ngủ hoặc nếu bạn đang dự định thực hiện chuỗi thực hiện không đồng bộ. Hãy sửa đổi nó để phù hợp với nhu cầu của bạn.

let sleeptime = 100
function* clock()
{
    let i = 0
    while( i <= 10000 )
    {
        i++
        console.log(i); // actually, just do stuff you wanna do.
        setTimeout(
            ()=>
            {
                clk.next()
            }
            , sleeptime
        )
        yield
    }
}

let clk = clock()
clk.next()

chức năng*

() => chức năng mũi tên

Bạn cũng có thể xâu chuỗi các sự kiện thông qua Lời hứa :

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


sleep(1000).then(function()
{
    console.log('1')
    sleep(1000).then(function()
    {
        console.log('2')
    })
})

Hoặc đơn giản hơn nhiều và một cách ít ưa thích hơn sẽ là

function sleep(ms, f)
{
    return(
        setTimeout(f, ms)
    )
}


sleep(500, function()
{
    console.log('1')
    sleep(500, function()
    {
        console.log('2')
    })
})
console.log('Event chain launched')

Nếu bạn chỉ chờ đợi một số điều kiện xảy ra, bạn có thể đợi như thế này

function waitTill(condition, thenDo)
{
    if (eval(condition))
    {
        thenDo()
        return
    }

    setTimeout(
        ()    =>
        {
            waitTill(condition, thenDo)
        }
        ,
        1
    )
}

x=0

waitTill(
    'x>2 || x==1'
    ,
    ()    =>
    {
        console.log("Conditions met!")
    }
)

// Simulating the change
setTimeout(
    () =>
    {
        x = 1
    }
    ,
    1000
)


11

Cập nhật 2018

Safari, Firefox và Node.js mới nhất hiện cũng hỗ trợ async / await / hứa hẹn.

Sử dụng async / await / Promise:

(Kể từ 1/2017, được hỗ trợ trên Chrome, nhưng không có trên Safari, Internet Explorer, Firefox, Node.js)

'use strict';

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

let myAsyncFunc = async function() {
  console.log('Sleeping');
  await sleep(3000);
  console.log('Done');
}

myAsyncFunc();

Cập nhật 2017

JavaScript đã phát triển kể từ khi câu hỏi này được hỏi và hiện có các hàm tạo và async / await / Promise mới đang được triển khai. Bên dưới có hai giải pháp, một giải pháp có chức năng tạo sẽ hoạt động trên tất cả các trình duyệt hiện đại và một giải pháp khác, sử dụng async / await mới chưa được hỗ trợ ở mọi nơi.

Sử dụng chức năng tạo:

'use strict';

let myAsync = (g) => (...args) => {
    let f, res = () => f.next(),
        sleep = (ms) => setTimeout(res, ms);
    f = g.apply({sleep}, args); f.next();
};

let myAsyncFunc = myAsync(function*() {
    let {sleep} = this;
    console.log("Sleeping");
    yield sleep(3000);
    console.log("Done");
});

myAsyncFunc();

Hãy chú ý đến thực tế là cả hai giải pháp này đều không đồng bộ về bản chất. Điều này có nghĩa là myAsyncFunc (trong cả hai trường hợp) sẽ trở lại trong khi ngủ.

Điều quan trọng cần lưu ý là câu hỏi này khác với phiên bản JavaScript của ngủ () là gì? trong đó người yêu cầu yêu cầu ngủ thực (không thực hiện mã nào khác trong quy trình) thay vì trì hoãn giữa các hành động.


1
Câu trả lời tốt nhất cho đến nay !! Tôi đã dành 30 phút tìm kiếm khắp nơi để tìm thấy điều đó .. thx lớn !!!
538ROMEO

1
Tôi đã bỏ lỡ câu trả lời này trong khi tìm kiếm một giải pháp và phát minh lại chiếc xe đạp: D Nếu tôi chỉ nhìn thấy nó trước khi nó sẽ giúp tôi tiết kiệm hàng giờ !! Nâng cao!
sserzant

let co = gen => (...args) => { let iter = gen(...args); let resume = () => new Promise((resolve, reject) => { let result = iter.next(); if (result.done) resolve(result.value); else Promise.resolve(result.value).then(resume).then(resolve, reject); }); return resume(); };sẽ cho phép bạn let asyncAdd = co(function* (a, b) { console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; }); asyncAdd(3, 4).then(console.log);sử dụng định nghĩa sleep()từ khối mã thứ hai của bạn.
Patrick Roberts

3

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, ...")


2

Một cách khác để làm điều đó là sử dụng Promise và setTimeout (lưu ý rằng bạn cần phải ở trong một hàm và đặt nó không đồng bộ với từ khóa async):

async yourAsynchronousFunction () {

    var a = 1+3;

    await new Promise( (resolve) => {
        setTimeout( () => { resolve(); }, 3000);
    }

    var b = a + 4;

}

2

Đây là một cách rất đơn giản để làm điều đó "cảm thấy" giống như một giấc ngủ / tạm dừng đồng bộ, nhưng là mã không đồng bộ js hợp pháp.

// Create a simple pause function
const pause = (timeoutMsec) => new Promise(resolve => setTimeout(resolve,timeoutMsec))

async function main () {
    console.log('starting');
    // Call with await to pause.  Note that the main function is declared asyc
    await pause(3*1000)
    console.log('done');
}


1

Bạn có thể sử dụng javascript đơn giản, điều này sẽ gọi chức năng / phương thức của bạn sau 5 giây:

setTimeout(()=> { your_function(); }, 5000);

0

Có một số cách để giải quyết vấn đề này. Nếu chúng ta sử dụng setTimeoutchức năng, hãy làm quen với nó trước. Hàm này có ba tham số: functionhoặc code, delay(tính bằng mili giây) và parameters. Vì tham số chức năng hoặc là bắt buộc, những cái khác là tùy chọn. Khi bạn chưa nhập độ trễ , nó sẽ được đặt thành không.

Để biết thêm chi tiết về việc setTimeout() đi đến liên kết này .

Phiên bản đơn giản hóa:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(function(){ 
    b = a + 4; 
    console.log('b = ' + b);
}, 1000);

đầu ra:
a = 4
24 -> Số nhận dạng của danh sách thời gian chờ hoạt động
b = 8


Sử dụng thông số vượt qua:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(myFunction, 1000, a);

function myFunction(a)
{
    var b = a + 4;
    console.log('b = ' + b);
}

đầu ra:
a = 4
25 -> Số nhận dạng của danh sách thời gian chờ hoạt động
b = 8



Hỗ trợ trình duyệt:

Chrome Firefox Edge Safari Opera
1.0 1.0 4.0 1.0 4.0

0

Đây là mô hình của tôi cho thấy cách "ngủ" hoặc "DoEvents" trong javascript bằng cách sử dụng chức năng tạo (ES6). Mã nhận xét:

<html>
<head>
<script>
  "use strict"; // always
  // Based on post by www-0av-Com /programming/3143928
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
  var divelt, time0, globaln = 0; // global variables
  var MainGenObj = Main(); // generator object = generator function()
window.onload = function() {
  divelt = document.getElementsByTagName("body")[0]; // for addline()
  addline("typeof Main: " + typeof Main);
  addline("typeof MainDriver: " + typeof MainDriver);
  addline("typeof MainGenObj: " + typeof MainGenObj);
  time0 = new Date().valueOf(); // starting time ms
  MainDriver(); // do all parts of Main()
}
function* Main() { // this is "Main" -- generator function -- code goes here
  // could be loops, or inline, like this:

  addline("Part A, time: " + time() + ", " + ++globaln); // part A
  yield 2000;                    // yield for 2000 ms (like sleep)

  addline("Part B, time: " + time() + ", " +  ++globaln); // part B
  yield 3000;                    // yield for 3000 ms (or like DoEvents)

  addline("Part Z, time: " + time() + ", " +  ++globaln); // part Z (last part)
  addline("End, time: " + time());
}
function MainDriver() { // this does all parts, with delays
  var obj = MainGenObj.next(); // executes the next (or first) part of Main()
  if (obj.done == false) { // if "yield"ed, this will be false
    setTimeout(MainDriver, obj.value); // repeat after delay
  }
}
function time() { // seconds from time0 to 3 decimal places
  var ret = ((new Date().valueOf() - time0)/1000).toString();
  if (ret.indexOf(".") == -1) ret += ".000";
  while (ret.indexOf(".") >= ret.length-3) ret += "0";
  return ret;
}
function addline(what) { // output
  divelt.innerHTML += "<br />\n" + what;
}
</script>
</head>
<body>
<button onclick="alert('I\'m alive!');"> Hit me to see if I'm alive </button>
</body>
</html>

0

Hãy thử chức năng này:

const delay = (ms, cb) => setTimeout(cb, ms)

Đây là cách bạn sử dụng nó:

console.log("Waiting for 5 seconds.")
delay(5000, function() {
  console.log("Finished waiting for 5 seconds.")
})

Hoặc đi theo kiểu hứa hẹn:

const delay = ms => new Promise(resolve => {
    setTimeout(resolve, ms)
})

Đây là một bản demo .

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.