ฉันจะรอใน Node.js (Javascript) ได้อย่างไรฉันต้องหยุดชั่วคราวเป็นระยะเวลาหนึ่ง


385

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

setTimeout(function() {
}, 3000);

อย่างไรก็ตามฉันต้องการทุกอย่างหลังจากบรรทัดของรหัสนี้เพื่อดำเนินการหลังจากช่วงเวลา

ตัวอย่างเช่น,

//start-of-code
console.log('Welcome to My Console,');
some-wait-code-here-for-ten-seconds..........
console.log('Blah blah blah blah extra-blah');
//endcode. 

ฉันเคยเห็นสิ่งต่าง ๆ เช่น

yield sleep(2000);

แต่ node.js ไม่รู้จักสิ่งนี้

ฉันจะบรรลุการหยุดชั่วคราวแบบขยายนี้ได้อย่างไร


3
ชำนาญเกี่ยวกับการที่คุณทำเครื่องหมายอย่างใดอย่างหนึ่งของคนเหล่านี้เป็นคำตอบที่ถูกต้อง :)
Billybonks

1
@ คริสโตเฟอร์อัลเลน, อาจจะไม่เกี่ยวข้อง แต่ทำหน้าที่ได้ดี: require("child_process").execSync('php -r "sleep($argv[1]);" ' + seconds);
Haitham Sweilem

โหนดนอนโมดูล NPM อาจทำเคล็ดลับ ( แต่ผมเท่านั้นที่จะใช้สำหรับการแก้จุดบกพร่อง)
จูเลียน Soro

คำตอบ:


211

วิธีที่ดีที่สุดในการทำเช่นนี้คือการแบ่งรหัสของคุณออกเป็นหลายฟังก์ชั่นดังนี้

function function1() {
    // stuff you want to happen right away
    console.log('Welcome to My Console,');
}

function function2() {
    // all the stuff you want to happen after that pause
    console.log('Blah blah blah blah extra-blah');
}

// call the first chunk of code right away
function1();

// call the rest of the code and have it execute after 3 seconds
setTimeout(function2, 3000);

มันคล้ายกับวิธีแก้ปัญหาของJohnnyHKแต่มีขนาดเล็กกว่าและขยายได้ง่ายกว่ามาก


7
@LucasSeveryn คุณทำอะไรผิดไป นี่คือรูปแบบการออกแบบหลัก
Elliot Bonneville

และคุณจะทำอย่างไรเมื่อจุดเริ่มต้นของฟังก์ชั่นไม่ได้เป็นเพียงแค่ฟังก์ชั่นเดียวเท่านั้น แต่ยังมี 10 ไฟล์จากรหัสที่จำเป็นต้องยกเลิกการซิงโครไนซ์?
Cyril Duchon-Doris

10
@ CyrilDuchon-Doris อะไรนะ?
AturSams

3
ใช้คำตอบของ @ machineghost สำหรับโซลูชันที่อิงตามคำสัญญาที่หรูหราซึ่งไม่จำเป็นต้องมีรหัสที่กำหนดเองและรองรับการรอคอย / async
Dane Macaulay

นี่คือ async หมายความว่าถ้า function1 ยกเลิกก่อน 3 วินาทีมันจะเริ่มทับซ้อนกัน ถ้าอย่างนั้นคุณก็ไม่สามารถกลับมาได้อีกและมันก็แทบจะไม่มีประโยชน์อะไรเลย วิธีเดียวที่ฉันพบจนถึงตอนนี้ก็คือการใช้debugger;
Cristian Traìna

427

คำตอบใหม่สำหรับคำถามเก่า วันนี้ ( มกราคม 2560มิถุนายน 2562) ง่ายกว่ามาก คุณสามารถใช้ใหม่async/awaitไวยากรณ์ ตัวอย่างเช่น:

async function init() {
  console.log(1);
  await sleep(1000);
  console.log(2);
}

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

สำหรับการใช้งานasync/awaitนอกกรอบโดยไม่ต้องติดตั้งและปลั๊กอินคุณต้องใช้ node-v7 หรือ node-v8 โดยใช้--harmonyแฟล็ก

อัปเดตมิถุนายน 2562:โดยการใช้ NodeJS เวอร์ชันล่าสุดคุณสามารถใช้งานได้ทันที ไม่จำเป็นต้องระบุอาร์กิวเมนต์บรรทัดคำสั่ง แม้แต่ Google Chrome ก็ยังรองรับอยู่ในปัจจุบัน

ปรับปรุงพฤษภาคม 2563: ในไม่ช้าคุณจะสามารถใช้awaitไวยากรณ์นอกฟังก์ชั่น async ได้ ในระดับสูงสุดเหมือนในตัวอย่างนี้

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

ข้อเสนอที่อยู่ในขั้นตอนที่ 3 คุณสามารถใช้งานได้แล้ววันนี้โดยใช้ webpack 5 (อัลฟา)

ข้อมูลเพิ่มเติม:


5
ฉันคิดว่าคุณลืมawaitคำหลักต่อหน้าsleep(1000)
Ryan Jarvis

6
นี่ควรเป็นคำตอบแพคเกจ sleep node.js อาจลำบาก
Stuart Allen

4
ทางออกที่ดีที่สุดแน่นอน
Kostas Siabanis

40
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms));สำหรับ freaks oneliner เหมือนตัวเอง :)
Predrag Stojadinović

21
let sleep = require('util').promisify(setTimeout);ใช้งานได้บนโหนด 7.6+ และปรับปรุงการอ่านได้ง่ายขึ้น
BrianHVB

216

ทางออกที่สั้นที่สุดโดยไม่ต้องพึ่งพาใด ๆ :

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

14
"ความสูงของความซับซ้อนคือความเรียบง่าย" - Clare Booth Luce นี่คือคำตอบที่ดีที่สุด IMO
arnold

3
เห็นได้ชัดว่านี่เป็นคำตอบล่าสุดมากกว่าคำตอบอื่น ๆ แต่มันก็เป็นสิ่งที่งดงามที่สุดในปี 2018 ที่ทำให้งานเสร็จใน 1 บรรทัดโดยไม่มีผลกระทบใด ๆ กับรหัส
Herick

1
นี่เป็นสิ่งที่ดี คุณต้องใช้ NodeJS 7.6.0 หรือสูงกว่า มันจะไม่ทำงานกับเวอร์ชั่นที่เก่ากว่า
Ryan Shillington

5
let sleep = require('util').promisify(setTimeout);มีความยาวสามตัวอักษร แต่สามารถนำกลับมาใช้ใหม่ได้และสามารถอ่านได้มากขึ้น
BrianHVB

2
เพื่อหลีกเลี่ยงการร้องเรียน eslint เรียกว่าแทนresolve doneIeawait new Promise(resolve => setTimeout(resolve, 5000))
Darren Cook

150

ใส่รหัสที่คุณต้องการดำเนินการหลังจากความล่าช้าในการsetTimeoutโทรกลับ:

console.log('Welcome to My Console,');
setTimeout(function() {
    console.log('Blah blah blah blah extra-blah');
}, 3000);

2
นี่เป็นความยุ่งเหยิงและการฝึกฝนที่ไม่ดีโดยเฉพาะอย่างยิ่งหาก OP ต้องการให้โปรแกรมที่เหลือทำงานหลังจากล่าช้า ดูคำตอบของฉัน
Elliot Bonneville

32
@ElliotBonneville เป็นเพียงตัวอย่างเพื่อแสดงแนวคิด เห็นได้ชัดว่าคุณสามารถ (ควร) ใส่รหัสลงในการเรียกใช้ฟังก์ชันแทนการใช้รหัสแบบอินไลน์เช่นเดียวกับที่อื่น
JohnnyHK

@ChristopherKemp: ปรากฎ Node.js node-fibersมีวิธีการนี้เรียกว่า ลองดูสิ
Elliot Bonneville

นี่เป็นทางออกที่ดีโดยเฉพาะอย่างยิ่งถ้าคุณไม่ต้องการรันโค้ดใด ๆ คุณเพียงแค่ต้องการเลียนแบบวิธี "sleep" ภายในลูป ไม่มีอะไรผิดปกติกับตัวอย่างนี้
Halfstop

นี้เหมาะสำหรับการล่าช้าในการร้องขอมาจากลูกค้าผมใช้วิธีนี้ในการทดสอบการปั่นด้ายการโหลดของฉันในฝั่งไคลเอ็นต์
Moein Rahimi

145

นี่เป็นเทคนิคการบล็อกอย่างง่าย:

var waitTill = new Date(new Date().getTime() + seconds * 1000);
while(waitTill > new Date()){}

มันกำลังบล็อกอยู่ตราบเท่าที่จะไม่มีสิ่งใดเกิดขึ้นในสคริปต์ของคุณ (เช่นการเรียกกลับ) แต่เนื่องจากนี่เป็นสคริปต์คอนโซลอาจเป็นสิ่งที่คุณต้องการ!


27
น่ากลัวหรือไม่มันง่ายwaitมันบล็อกและใช้งานได้เพื่อวัตถุประสงค์ในการทดสอบบางอย่าง สิ่งที่ฉันกำลังค้นหา
Clijsters

8
ตอบคำถามได้อย่างสมบูรณ์แบบโดยไม่มี libs ของบุคคลที่สามและเป็นเรื่องง่าย ยังมีคนพูดว่า "น่ากลัว" .... นี่เป็นตัวอย่างที่ดีมากสำหรับการจำลองภาระซีพียูหนัก ฯลฯ Btw คล้ายกันมากกับphpied.com/sleep-in-javascript
Don Cheadle

2
นี่เป็นวิธีการที่จำเป็นหากคุณพยายามจำลองบางสิ่งที่อาจทำให้เกิดการวนซ้ำของเหตุการณ์ทำให้ผู้ใช้ / การเชื่อมต่ออื่น ๆ ช้าลงเช่นกัน การเพิ่มการโทรกลับล่าช้าจะไม่ส่งผลกระทบต่อผู้ใช้ / การเชื่อมต่ออื่น ๆ
Don Cheadle

13
spin-waitนี่คือ
Mike Atlas

7
@ Ali ที่ดูเหมือนจะเป็นเป้าหมาย
Félix Gagnon-Grenier

63

บน Node 7.6.0 หรือสูงกว่า

โหนดรองรับการรอคอย:

const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));

ถ้าคุณสามารถใช้ฟังก์ชัน async ได้:

await sleep(10000); // sleep for 10 seconds

หรือ:

sleep(10000).then(() => {
  // This will execute 10 seconds from now
});

ในรุ่นโหนดเก่า (คำตอบเดิม)

ฉันต้องการการนอนแบบอะซิงโครนัสที่ทำงานใน Windows & Linux โดยไม่ต้องใช้ซีพียูในขณะที่วนซ้ำ ฉันลองแพคเกจสลีปแล้ว แต่จะไม่ติดตั้งลงในกล่อง Windows ของฉัน ฉันสิ้นสุดการใช้:

https://www.npmjs.com/package/system-sleep

หากต้องการติดตั้งให้พิมพ์:

npm install system-sleep

ในรหัสของคุณ

var sleep = require('system-sleep');
sleep(10*1000); // sleep for 10 seconds

ทำงานเหมือนจับใจ


1
คำตอบที่ดีขอบคุณ - มันทำให้บางอย่างเป็นไปไม่ได้รหัส - นี่ไม่ใช่การรอหมุน
danday74

1
ในการวิจัยเพิ่มเติมโมดูลนี้อาศัย deasync ซึ่งแยกจาก deasync github repo อื่น repo ดั้งเดิมเตือนว่าอย่าใช้เพราะมันเป็นแฮ็ค มันใช้งานได้ แต่ไม่ได้อยู่ในทุกแพลตฟอร์มดังนั้นหากคุณต้องการโซลูชันข้ามแพลตฟอร์มให้หลีกเลี่ยงปัญหานี้
danday74

1
ใช่ฉันไม่เคยมีประสบการณ์กับมันและมันยอดเยี่ยมสำหรับ dev - ภายใต้ประทุนฉันเชื่อว่ามันต้องอาศัย C หรือ C ++ ซึ่งมีให้ใช้กันอย่างแพร่หลาย แต่ฉันเดาว่าเครื่องบางอย่างมันไม่ได้เป็นอย่างนั้น - หากระบบไม่ทำงานโหมดสลีปจะกลับเป็นการรอการหมุนซึ่งจะหยุดการประมวลผลโค้ด
danday74

1
แพคเกจนี้ใช้ไม่ได้กับ Mac OS และดังนั้นจึงไม่สามารถใช้งานร่วมกันได้และไม่สามารถใช้งานได้ ดูgithub.com/jochemstoel/nodejs-system-sleep/issues/4
nuzzolilo

1
@Nuzzolilo นั่นแปลก เรามีผู้พัฒนาหนึ่งรายใน Mac OS และเขาไม่เคยพูดถึงสิ่งใดเลย ฉันสงสัยว่าเป็นรุ่น Mac OS ที่เฉพาะเจาะจง ฉันได้อัปเดตคำตอบนี้ด้วยเนื่องจากการสลีปนั้นสร้างขึ้นใน NodeJS เวอร์ชันใหม่กว่า
Ryan Shillington

62

ฟังก์ชั่นการนอนหลับที่เรียบง่ายและสง่างามโดยใช้ Javascript ที่ทันสมัย

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

ไม่มีการพึ่งพาไม่มีการเรียกกลับนรก แค่นั้นแหละ :-)


เมื่อพิจารณาตัวอย่างที่ให้มาในคำถามนี่คือวิธีที่เราจะพักระหว่างสองบันทึกของคอนโซล:

async function main() {
    console.log("Foo");
    await sleep(2000);
    console.log("Bar");
}

main();

"ข้อเสียเปรียบ" ก็คือฟังก์ชั่นหลักของคุณในตอนนี้ก็asyncเช่นกัน แต่เมื่อพิจารณาว่าคุณกำลังเขียนโค้ด Javascript ที่ทันสมัยอยู่แล้วคุณอาจจะ (หรืออย่างน้อยก็ควรจะเป็น!) โดยใช้async/ awaitทั่วรหัสของคุณดังนั้นนี่จึงไม่ใช่ปัญหา ทุกเบราว์เซอร์ที่ทันสมัยในปัจจุบันการสนับสนุนมัน

ให้ข้อมูลเชิงลึกเล็กน้อยเกี่ยวกับsleepฟังก์ชั่นสำหรับผู้ที่ไม่ได้ใช้async/awaitและผู้ประกอบการลูกศรไขมันนี่คือวิธีการเขียนอย่างละเอียด:

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

อย่างไรก็ตามการใช้ตัวดำเนินการลูกศรไขมันทำให้มันมีขนาดเล็กลง (และสวยงามยิ่งขึ้น)


1
นอกจากนี้คุณยังสามารถเขียนฟังก์ชั่นการนอนหลับโดยไม่ต้องasyncและปล่อยให้ทุกอย่างอื่นเหมือนกัน มันอาจจะเป็นที่ชัดเจนกับasyncว่า
Kevin Peña

เยี่ยมมาก @ KevinPeña asyncเรื่องของความเป็นจริงฉันคิดว่าฉันต้องการได้โดยไม่ต้อง แก้ไขคำตอบของฉันด้วยคำแนะนำของคุณ ฉันไม่คิดว่ามันจะทำให้รหัสชัดเจนขึ้น เพื่อที่ฉันจะหันไปใช้ JSDoc แทน
Lucio Paiva

8
ฉันชอบที่จะมีหนึ่งซับในสคริปต์ของฉัน:const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
korya

46

คุณสามารถใช้www.npmjs.com/package/sleep

var sleep = require('sleep');
sleep.sleep(10); // sleep for ten seconds

4
มันทำงานได้ดีบนMacOSแต่ก็พบข้อผิดพลาดในCentOSเนื่องจากข้อผิดพลาด node_gyp ดูเหมือนพกพาไม่ได้
AechoLiu

1
อาจเป็นปัญหาที่เกิดจาก OS ไม่ได้ แต่เกิดจากการสร้างโหนด
Aleksej

34

คำถามนี้ค่อนข้างเก่า แต่เมื่อเร็ว ๆ นี้ V8 ได้เพิ่มเครื่องกำเนิดไฟฟ้าซึ่งสามารถทำสิ่งที่ OP ต้องการได้ เครื่องกำเนิดไฟฟ้าโดยทั่วไปมักจะง่ายที่สุดที่จะใช้สำหรับการติดต่อ async ด้วยความช่วยเหลือของห้องสมุดเช่นระงับหรือGEN-วิ่ง

นี่คือตัวอย่างการใช้การระงับ:

suspend(function* () {
    console.log('Welcome to My Console,');
    yield setTimeout(suspend.resume(), 10000); // 10 seconds pass..
    console.log('Blah blah blah blah extra-blah');
})();

การอ่านที่เกี่ยวข้อง (โดยวิธีการส่งเสริมตนเองที่ไร้ยางอาย): เรื่องใหญ่กับเครื่องกำเนิดไฟฟ้าคืออะไร? .


2
คำตอบที่ดี - แต่ควรอ่านyield setTimeout(suspend.resume(), 10000);
edhubbell

1
ขอบคุณ @edhubbell คำตอบนี้ขึ้นอยู่กับการระงับเวอร์ชันเก่ามาก แต่คุณพูดถูกเกี่ยวกับข้อมูลล่าสุด ฉันจะอัปเดตคำตอบ
jmar777

โหนดรุ่นนี้มีไว้ทำอะไร?
danday74

1
@ danday74 ฉันจำไม่ได้ว่าเมื่อพวกเขาไม่ถูกตั้งค่าสถานะ แต่พวกเขาอยู่ที่นั่นตั้งแต่ v0.12 หลัง--harmonyธงและตาม node.green อย่างน้อยพวกเขาก็สามารถใช้งานได้โดยไม่มีธงตั้งแต่ v4.8.4: node.green/#ES2015-functions-generators-basic-functionality อย่างไรก็ตามโปรดทราบว่าasync/awaitไวยากรณ์ที่ใหม่กว่านั้นเป็นทางออกที่ดีกว่าสำหรับตอนนี้โดยไม่จำเป็นต้องมีsuspendไลบรารี่เพิ่มเติม ดูคำตอบนี้สำหรับตัวอย่าง: stackoverflow.com/a/41957152/376789 ฟังก์ชั่น Async มีให้ใช้งาน (ไม่มีแฟล็ก) ตั้งแต่ v7.10
jmar777

20

บน Linux / nodejs สิ่งนี้ใช้ได้กับฉัน:

const spawnSync = ต้องการ ('child_process') spawnSync;

var sleep = spawnSync ('sleep', [1.5]);

มันกำลังบล็อก แต่มันไม่ใช่การรอคอยที่ไม่ว่าง

เวลาที่คุณระบุเป็นวินาที แต่อาจเป็นเศษส่วน ฉันไม่รู้ว่าระบบปฏิบัติการอื่นมีคำสั่งที่คล้ายกันหรือไม่


sleepเป็นอยู่ทั่วไปทุกหนทุกแห่งสวยมากและ arround utiltiy ตั้งแต่วัน UNIX ต้นen.wikipedia.org/wiki/Sleep_%28Unix%29 เฉพาะระบบปฏิบัติการที่ "ไม่ได้หายาก" มันอาจไม่มีอยู่จริงคือ windows (อย่างไรก็ตามคุณสามารถลองได้child_process.spawnSync('timeout', ['/T', '10'])
humanityANDpeace

17

หากคุณต้องการ "code golf" คุณสามารถสร้างคำตอบสั้น ๆ ได้ที่นี่:

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

แต่จริงๆคำตอบที่ดีที่สุดในความคิดของฉันคือการใช้utilห้องสมุดของ Node และpromisifyฟังก์ชั่นของมันซึ่งได้รับการออกแบบมาสำหรับสิ่งนี้ (ทำรุ่นตามสัญญาของสิ่งที่ไม่ใช่สัญญาที่มีอยู่ก่อนหน้านี้):

const util = require('util');
const sleep = util.promisify(setTimeout);

ในกรณีใดกรณีหนึ่งจากนั้นคุณสามารถหยุดเพียงแค่ใช้awaitเพื่อเรียกsleepใช้ฟังก์ชันของคุณ:

await sleep(1000); // sleep for 1s/1000ms

ที่จริงแล้วการใช้ util.promisify เป็นไปไม่ได้ที่จะเรียกการนอนหลับโดยไม่ให้โทรกลับ nodejs.org/api/…
Howie

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

1
เขียนเป็นบรรทัดเดียวเพื่อเขียนโค้ดกอล์ฟ;) const sleep = require ('util'). promisify (setTimeout);
เฟเบียน

14

ฉันเพิ่งสร้างนามธรรมที่ง่ายกว่าที่เรียกว่าwait.forเพื่อเรียกใช้ฟังก์ชัน async ในโหมดซิงค์ (ขึ้นอยู่กับโหนดของเส้นใย) นอกจากนี้ยังมีรุ่นตาม ES6 Generators ที่กำลังจะมาถึง

https://github.com/luciotato/waitfor

การใช้wait.forคุณสามารถเรียกใช้ฟังก์ชัน async nodejs มาตรฐานใด ๆ ราวกับว่ามันเป็นฟังก์ชั่นการซิงค์โดยไม่ปิดกั้นลูปเหตุการณ์ของโหนด

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

ใช้wait.forรหัสของคุณจะเป็น:

require('waitfor')

..in a fiber..
//start-of-code
console.log('Welcome to My Console,');
wait.miliseconds(10*1000); //defined in waitfor/paralell-tests.js - DOES NOT BLOCK
console.log('Blah blah blah blah extra-blah');
//endcode. 

นอกจากนี้ยังสามารถเรียกใช้ฟังก์ชัน async ใด ๆ ในโหมดซิงค์ ตรวจสอบตัวอย่าง


TypeError: Object #<Object> has no method 'miliseconds'
CaffeineAddiction

ความคิดเห็นพูดว่า: "// กำหนดใน waitfor / paralell-tests.js" คว้ามันจากไฟล์นั้น
Lucio M. Tato

2
หลังจากที่ฉันได้รับจากwait.for/paralell-tests.jsฉันพบข้อผิดพลาดอื่นที่เกี่ยวข้องกับคุณสมบัติที่ไม่ได้กำหนดเป็นต้นดังนั้นฉันจึงจำเป็นต้องคัดลอกมันด้วย ทำไมคุณไม่จัดระเบียบรหัสในลักษณะที่ไม่จำเป็นต้องใช้?
user907860

Wait.for และโซลูชันเส้นใยอื่น ๆ ได้เปิดโลกใหม่ให้ฉัน! ฉันจะลงคะแนนนี้เป็นล้านครั้งถ้าทำได้ แม้ว่าชุมชน nodejs ส่วนใหญ่จะต่อต้านเส้นใย แต่ฉันคิดว่าพวกมันน่าทึ่งและมีที่ที่แน่นอนเมื่อพูดถึงนรกแห่งการติดต่อกลับ
Levi Roberts

7

เนื่องจากเอ็นจิ้น javascript (v8) รันโค้ดตามลำดับเหตุการณ์ในคิวเหตุการณ์จึงไม่เข้มงวดที่จาวาสคริปต์จะเรียกใช้การทำงานในเวลาที่กำหนด นั่นคือเมื่อคุณตั้งค่าบางวินาทีเพื่อรันโค้ดในภายหลังรหัสทริกเกอร์จะขึ้นอยู่กับลำดับในคิวเหตุการณ์ ดังนั้นการเรียกใช้รหัสอาจใช้เวลาเกินกว่าที่กำหนด

ดังนั้น Node.js ดังนี้

process.nextTick()

เพื่อเรียกใช้รหัสในภายหลังแทน setTimeout () ตัวอย่างเช่น,

process.nextTick(function(){
    console.log("This will be printed later");
});

2

ด้วยการรองรับ ES6 Promiseเราสามารถใช้มันได้โดยไม่ต้องขอความช่วยเหลือจากบุคคลที่สาม

const sleep = (seconds) => {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, (seconds * 1000));
    });
};

// We are not using `reject` anywhere, but it is good to
// stick to standard signature.

จากนั้นใช้แบบนี้:

const waitThenDo(howLong, doWhat) => {
    return sleep(howLong).then(doWhat);
};

โปรดทราบว่าdoWhatฟังก์ชั่นกลายเป็นโทรกลับภายในresolvenew Promise(...)

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

https://github.com/erikdubbelboer/node-sleep


1
let co = require('co');
const sleep = ms => new Promise(res => setTimeout(res, ms));

co(function*() {
    console.log('Welcome to My Console,');
    yield sleep(3000);
    console.log('Blah blah blah blah extra-blah');
});

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

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


ในขณะที่รหัสนี้อาจตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือทำไมมันแก้ปัญหาจะปรับปรุงค่าระยะยาวของคำตอบ
Donald Duck

ขอบคุณ @DonaldDuck รหัสในคำตอบของฉันน่าจะเป็นส่วนที่น่าตื่นเต้นที่สุดในการปรับปรุง Javascript ฉันประหลาดใจมากที่บางคนฉลาดสุดคิดเกี่ยวกับวิธีนี้เพื่อแก้ปัญหานรกโทรกลับ
Qian Chen

1

นี่คือ moment.js รสโมดูลบนพื้นฐานของความสกปรกวิธีการปิดกั้นการแนะนำโดย @ ใช้สำหรับการทดสอบเท่านั้น

const moment = require('moment');

let sleep = (secondsToSleep = 1) => {
    let sleepUntill = moment().add(secondsToSleep, 'seconds');
    while(moment().isBefore(sleepUntill)) { /* block the process */ }
}

module.exports = sleep;

0

หากคุณเพียงแค่ต้องระงับเพื่อการทดสอบคุณดำเนินการหัวข้อปัจจุบันลองนี้:

function longExecFunc(callback, count) {

    for (var j = 0; j < count; j++) {
        for (var i = 1; i < (1 << 30); i++) {
            var q = Math.sqrt(1 << 30);
        }
    }
    callback();
}
longExecFunc(() => { console.log('done!')}, 5); //5, 6 ... whatever. Higher -- longer

0

ง่าย ๆ เราจะรอ 5 วินาทีเพื่อให้เหตุการณ์บางอย่างเกิดขึ้น (ซึ่งจะถูกระบุโดยตัวแปรที่ทำเสร็จแล้วตั้งค่าเป็นจริงที่อื่นในรหัส) หรือเมื่อหมดเวลาหมดอายุที่เราจะตรวจสอบทุก ๆ 100ms

    var timeout=5000; //will wait for 5 seconds or untildone
    var scope = this; //bind this to scope variable
    (function() {
        if (timeout<=0 || scope.done) //timeout expired or done
        {
            scope.callback();//some function to call after we are done
        }
        else
        {
            setTimeout(arguments.callee,100) //call itself again until done
            timeout -= 100;
        }
    })();

0

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

var hello = "Hello World";
setTimeout(alert, 1000, hello); 

'hello' คือพารามิเตอร์ที่ส่งผ่านคุณสามารถผ่านพารามิเตอร์ทั้งหมดได้หลังจากหมดเวลา ขอบคุณ @Fabio Phms สำหรับคำตอบ


0

แทนที่จะใช้ setTimeout, sleep และสิ่งอื่น ๆ ทั้งหมดเหล่านี้ควรใช้

const delay = require('delay');
await delay(2000); // will wait for 2 seconds before executing next line of code

คุณสามารถอธิบายได้ว่า 'ล่าช้า' คืออะไรและเชื่อมโยงไปยังเอกสารของมันหรือไม่ ทำไมจะดีกว่า
boycy

-2

คำตอบอื่น ๆ ที่ดี แต่ฉันคิดว่าฉันจะใช้ไหวพริบที่แตกต่างกัน

หากสิ่งที่คุณกำลังมองหาจริงๆคือการชะลอไฟล์เฉพาะใน linux:

 rm slowfile; mkfifo slowfile; perl -e 'select STDOUT; $| = 1; while(<>) {print $_; sleep(1) if (($ii++ % 5) == 0); }' myfile > slowfile  &

node myprog slowfile

สิ่งนี้จะนอน 1 วินาทีทุกห้าบรรทัด โปรแกรมโหนดจะทำงานช้ากว่าตัวเขียน หากทำสิ่งอื่น ๆ พวกเขาจะดำเนินการต่อด้วยความเร็วปกติ

mkfifo สร้างไพพ์แบบเข้าก่อนออกก่อน มันเป็นสิ่งที่ทำให้งานนี้ บรรทัด Perl จะเขียนเร็วเท่าที่คุณต้องการ $ | = 1 บอกว่าอย่าบัฟเฟอร์เอาต์พุต


-3

ฉันรวบรวมกันหลังจากอ่านคำตอบในคำถามนี้แล้วฟังก์ชั่นเรียบง่ายซึ่งสามารถโทรกลับได้ถ้าคุณต้องการ:

function waitFor(ms, cb) {
  var waitTill = new Date(new Date().getTime() + ms);
  while(waitTill > new Date()){};
  if (cb) {
    cb()
  } else {
   return true
  }
}

-4

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ

yield sleep(2000); 

คุณควรตรวจสอบRedux-Saga แต่มันก็มีความเฉพาะกับ Redux ที่คุณเลือกเป็นกรอบโมเดลของคุณ (แม้ว่าจะไม่จำเป็นอย่างยิ่ง)

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