สลีปใน JavaScript - หน่วงเวลาระหว่างการดำเนินการ


130

มีวิธีใดบ้างที่ฉันสามารถเข้าสู่โหมดสลีปใน JavaScript ก่อนที่จะดำเนินการอื่น

ตัวอย่าง:

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

คำตอบ:


140

คุณสามารถใช้setTimeoutเพื่อให้ได้เอฟเฟกต์ที่คล้ายกัน:

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

สิ่งนี้ไม่ได้ 'สลีป' JavaScript จริงๆเพียงแค่เรียกใช้ฟังก์ชันที่ส่งผ่านไปsetTimeoutหลังจากช่วงเวลาหนึ่ง (ระบุเป็นมิลลิวินาที) แม้ว่าจะสามารถเขียนฟังก์ชันสลีปสำหรับ JavaScript ได้ แต่ควรใช้setTimeoutหากเป็นไปได้เนื่องจากจะไม่หยุดทุกอย่างในช่วงเวลาพักเครื่อง


9
ดูที่ setInterval () ด้วย คล้ายกับ setTimeout () แต่ฟังก์ชันของคุณถูกเรียกใช้หลายครั้ง (จนกว่าคุณจะหยุด) ซึ่งจะมีประโยชน์หากคุณต้องการทำอะไรบางอย่างขณะนอนหลับ (เช่นการอัปเดตความคืบหน้าการรักษาสถานะภายในหรืออะไรก็ตาม)
Anders Sandvig

5
สิ่งนี้ไม่ตอบคำถาม คำถามขอให้เทียบเท่า "การนอนหลับ" ซึ่งไม่ใช่
felwithe

แม้ว่าคำตอบนี้จะไม่ตรงกับคำถามที่ถาม แต่ก็มีประโยชน์มากกว่าการวนซ้ำและเปรียบเทียบ Date.now () ไม่มีสิ่งใดที่จะใช้ลูปที่ถูกบล็อกในการใช้งานสลีป
Li Chunlin

2
เว้นแต่ของหลักสูตรที่วงปิดกั้นเป็นว่าสิ่งที่ต้องการใครสักคน
Wonko the Sane

55

ในกรณีที่คุณต้องการsleep()เพียงแค่ทดสอบบางอย่าง แต่โปรดทราบว่าเบราว์เซอร์จะขัดข้องเกือบตลอดเวลาในขณะที่ debuggin - นั่นอาจเป็นเหตุผลว่าทำไมคุณถึงต้องการ ในโหมดการผลิตฉันจะแสดงความคิดเห็นเกี่ยวกับฟังก์ชันนี้

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

อย่าใช้new Date()วนซ้ำเว้นแต่ว่าคุณต้องการใช้หน่วยความจำพลังงานในการประมวลผลแบตเตอรี่และอาจถึงอายุการใช้งานของอุปกรณ์ของคุณ


8
คำตอบนี้สมควรได้รับการโหวตมากขึ้น การติดดาวคำถามเป็นเพียงสาเหตุของคำตอบนี้
jagc

แล้วคำเตือน "การเรียกซ้ำมากเกินไป" ล่ะ
Oki Erie Rinaldi

1
@OkiErieRinaldi ไม่มีการเรียกซ้ำที่นั่นเป็นเพียงการวนซ้ำ
Rodrigo

7
@ 3.1415926535897932384626433833 มีบางคนขอฟังก์ชัน "นอนหลับ" นั่นคือสิ่งที่นี่ เคยใช้ครั้งเดียวจำไม่ได้แล้วว่าใช้ดีบั๊กแบบไหน ถ้าฉันต้องการอีกครั้งฉันรู้ว่าจะหาได้ที่ไหน หากคุณต้องการฟังก์ชั่นอื่นนั่นเป็นทางเลือกของคุณ มันไม่ดีที่จะสามารถเลือก?
Rodrigo

2
"ไม่ว่างรอ".
Zeek2

13

ECMAScript 6 เวอร์ชันโดยใช้เครื่องกำเนิดไฟฟ้าที่มีผลตอบแทนสำหรับ "การบล็อกโค้ด":

เนื่องจากคำถามเดิมถูกโพสต์เมื่อเจ็ดปีที่แล้วฉันจึงไม่รำคาญที่จะตอบด้วยรหัสที่แน่นอนเพราะมันง่ายเกินไปและได้รับคำตอบแล้ว สิ่งนี้จะช่วยในปัญหาที่ซับซ้อนมากขึ้นเช่นหากคุณต้องการอย่างน้อยสองโหมดสลีปหรือหากคุณกำลังวางแผนที่จะจัดลำดับการดำเนินการแบบอะซิงโครนัส อย่าลังเลที่จะปรับเปลี่ยนให้เหมาะกับความต้องการของคุณ

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()

ฟังก์ชั่น *

() => ฟังก์ชันลูกศร

นอกจากนี้คุณยังสามารถเชื่อมโยงเหตุการณ์ผ่านสัญญา :

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')
    })
})

หรือง่ายกว่ามากและเป็นวิธีแฟนซีน้อยกว่า

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')

หากคุณกำลังรอให้เงื่อนไขบางอย่างเกิดขึ้นคุณสามารถรอแบบนี้ได้

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

อัปเดต 2018

Safari, Firefox และ Node.js ล่าสุดยังรองรับ async / await / promises

ใช้ async / await / Promises:

(ณ วันที่ 1/2560 รองรับบน Chrome แต่ไม่ใช่บน 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();

อัปเดต 2017

JavaScript มีการพัฒนาตั้งแต่คำถามนี้ถูกถามและตอนนี้มีฟังก์ชันตัวสร้างและ async / await / Promise ใหม่กำลังเปิดตัว ด้านล่างนี้มีสองโซลูชันหนึ่งที่มีฟังก์ชันตัวสร้างที่จะทำงานบนเบราว์เซอร์ที่ทันสมัยทั้งหมดและอีกวิธีหนึ่งใช้ async / await ใหม่ที่ยังไม่รองรับทุกที่

การใช้ฟังก์ชันเครื่องกำเนิดไฟฟ้า:

'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();

ให้ความสนใจกับข้อเท็จจริงที่ว่าโซลูชันทั้งสองนี้เป็นแบบอะซิงโครนัส ซึ่งหมายความว่า myAsyncFunc (ในทั้งสองกรณี) จะกลับมาขณะนอนหลับ

สิ่งสำคัญคือต้องทราบว่าคำถามนี้แตกต่างจากสลีปเวอร์ชัน JavaScript คืออะไร? โดยที่ผู้ร้องขอกำลังขอการนอนหลับจริง (ไม่มีการเรียกใช้รหัสอื่น ๆ ในกระบวนการ) แทนที่จะเป็นความล่าช้าระหว่างการดำเนินการ


1
ตอบโจทย์สุด ๆ !! ฉันใช้เวลา 30 นาทีในการค้นหาทุกที่เพื่อพบว่า .. ขอบคุณมาก !!!
538ROMEO

1
ฉันพลาดคำตอบนี้ในขณะที่กำลังมองหาวิธีแก้ปัญหาและคิดค้นจักรยานขึ้นมาใหม่: D ถ้าฉันเห็นมันก่อนที่มันจะช่วยฉันได้หลายชั่วโมง !! upvoted!
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(); };จะช่วยให้คุณlet asyncAdd = co(function* (a, b) { console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; }); asyncAdd(3, 4).then(console.log);ใช้คำจำกัดความของsleep()จากบล็อกรหัสที่สองของคุณ
Patrick Roberts

3

หากคุณต้องการฟังก์ชั่น clunky น้อยกว่าsetTimeoutและsetIntervalคุณสามารถรวมไว้ในฟังก์ชันที่ย้อนกลับลำดับของอาร์กิวเมนต์และตั้งชื่อที่ดีได้:

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

เวอร์ชัน CoffeeScript:

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

จากนั้นคุณสามารถใช้งานได้ดีกับฟังก์ชันที่ไม่ระบุชื่อ:

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

ตอนนี้อ่านง่าย ๆ ว่า "หลังจาก N มิลลิวินาที, ... " (หรือ "ทุกๆ N มิลลิวินาที, ... ")


2

อีกวิธีในการทำเช่นนี้คือการใช้ Promise และ setTimeout (โปรดทราบว่าคุณต้องอยู่ในฟังก์ชันและตั้งค่าแบบอะซิงโครนัสด้วยคีย์เวิร์ด async):

async yourAsynchronousFunction () {

    var a = 1+3;

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

    var b = a + 4;

}

2

นี่เป็นวิธีที่ง่ายมากที่จะทำให้ 'รู้สึก' เหมือนการนอนหลับ / หยุดชั่วคราวแบบซิงโครนัส แต่เป็นรหัส async ที่ถูกต้อง js

// 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

คุณสามารถใช้จาวาสคริปต์ธรรมดาสิ่งนี้จะเรียกใช้ฟังก์ชัน / วิธีการของคุณหลังจาก 5 วินาที:

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

0

มีหลายวิธีในการแก้ปัญหานี้ ถ้าเราใช้setTimeoutฟังก์ชั่นเรามาทำความรู้จักกับมันก่อน ฟังก์ชั่นนี้มีสามพารามิเตอร์: functionหรือcode, delay(มิลลิวินาที) parametersและ เนื่องจากจำเป็นต้องมีฟังก์ชันหรือพารามิเตอร์โค้ดส่วนอื่น ๆ จึงเป็นทางเลือก เมื่อคุณไม่ได้ป้อนการหน่วงเวลาจะถูกตั้งค่าเป็นศูนย์

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับsetTimeout() ไปที่ลิงค์นี้

เวอร์ชันที่เรียบง่าย:

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

เอาต์พุต:
a = 4
24 -> ตัวระบุหมายเลขของรายการการหมดเวลาที่ใช้งานอยู่
b = 8


การใช้พารามิเตอร์ผ่าน:

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);
}

เอาต์พุต:
a = 4
25 -> ตัวระบุหมายเลขของรายการระยะหมดเวลาที่ใช้งานอยู่
b = 8



รองรับเบราว์เซอร์:

Chrome Firefox Edge Safari Opera
1.0 1.0 4.0 1.0 4.0

0

นี่คือโมเดลของฉันที่แสดงวิธี "sleep" หรือ "DoEvents" ใน javascript โดยใช้ฟังก์ชัน Generator (ES6) รหัสแสดงความคิดเห็น:

<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

ลองใช้ฟังก์ชันนี้:

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

นี่คือวิธีที่คุณใช้:

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

หรือไปสไตล์สัญญา:

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

นี่คือการสาธิต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.