Apa itu versi tidur JavaScript ()?

2335

Apakah ada cara yang lebih baik untuk merekayasa sleepdalam JavaScript daripada pausecompfungsi berikut ( diambil dari sini )?

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

Ini bukan duplikat Tidur di JavaScript - penundaan antar tindakan ; Saya ingin tidur nyata di tengah fungsi, dan bukan penundaan sebelum sepotong kode dijalankan.

fmsf
sumber
4
Ini diatur di tengah-tengah sementara, jika saya menggunakan setTimeout sementara itu akan terus memproses dan mengantri lebih banyak setTimeouts yang akhirnya akan berjalan pada waktu yang sama dan membuat sedikit konkurensi di antara mereka sendiri
fmsf
160
Ini adalah solusi yang mengerikan - Anda akan mengunyah siklus pemrosesan sambil tidak melakukan apa pun.
17 dari 26
12
Satu-satunya tujuan tidur adalah polling atau menunggu panggilan balik - setInterval dan setTimeout melakukan keduanya lebih baik dari ini.
annakata
1
Mungkin Anda dapat melakukan apa yang Anda inginkan dengan gaya passing berkelanjutan dalam JavaScript. Lihatlah artikel ini.
Ognyan Dimitrov

Jawaban:

2563

2017 - 2019 pembaruan

Sejak 2009 ketika pertanyaan ini diajukan, JavaScript telah berevolusi secara signifikan. Semua jawaban lain sekarang sudah usang atau terlalu rumit. Inilah praktik terbaik saat ini:

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

Ini dia. await sleep(<duration>).

Atau sebagai one-liner:

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

Perhatikan bahwa,

  1. awaithanya dapat dieksekusi dalam fungsi yang diawali dengan asynckata kunci, atau di tingkat atas skrip Anda di beberapa lingkungan (mis. konsol Chrome DevTools, atau Runkit).
  2. awaithanya menjeda asyncfungsi saat ini

Dua fitur JavaScript baru membantu menulis fungsi "tidur" ini:

Kesesuaian

Jika karena alasan yang aneh Anda menggunakan Node yang lebih tua dari 7 (yang telah mencapai akhir masa pakai ), atau menargetkan browser lama, async/ awaitmasih dapat digunakan melalui Babel (alat yang akan mengubah - ubah JavaScript + fitur-fitur baru menjadi JavaScript lama biasa) , dengan transform-async-to-generatorplugin.

Dan Dascalescu
sumber
5
Barang bagus di sini. Saya bertanya-tanya, bagaimana hal ini memengaruhi atau berhubungan dengan peramban modern "aktif" / "tidak aktif" setelah JS menyebut mode "tidur"? Bisakah browser memblokir tidur seperti yang diharapkan untuk JS umum, untuk mengingat nanti ketika menjadi "aktif", atau apakah ia memiliki perilaku yang berbeda?
Andre Canilho
18
Apa dukungan browser saat ini untuk ini? Saya tidak akan menganggap solusi sebelumnya sebagai "usang" sampai solusi ini didukung oleh sebagian besar browser, atau setidaknya semua yang umum. Sebaliknya, saya akan menganggap solusi ini menarik tetapi tidak dapat digunakan / tidak praktis sampai memiliki dukungan luas.
Alvin Thompson
75
Ini bukan "tidur nyenyak" dan tidak menjawab pertanyaan. Orang yang bertanya membuat perbedaan yang jelas antara stackoverflow.com/questions/758688/sleep-in-javascript dan pertanyaannya. Dalam tidur nyenyak tidak ada kode lain yang dapat dieksekusi (kecuali di utas lainnya). Jawaban ini bagus untuk pertanyaan lainnya.
niry
4
@ jacroe - transpiler menangani fungsi panah dan juga async / menunggu (yang akan menyebabkan IE muntah darah)
Jaromanda X
11
@niry JavaScript, menjadi bahasa utas tunggal, tidak cocok untuk tidur "nyata", karena berjalan pada utas yang sama dengan UI dan akan menyebabkan halaman web tidak responsif.
Patrick Roberts
849

(Lihat jawaban yang diperbarui untuk 2016 )

Saya pikir sangat masuk akal untuk ingin melakukan suatu tindakan, tunggu, lalu lakukan tindakan lain. Jika Anda terbiasa menulis dalam bahasa multi-utas, Anda mungkin memiliki ide untuk menghasilkan eksekusi untuk waktu yang ditentukan hingga utas Anda terbangun.

Masalahnya di sini adalah bahwa JavaScript adalah model berbasis peristiwa single-thread. Sementara dalam kasus tertentu, mungkin menyenangkan untuk membiarkan seluruh mesin menunggu beberapa detik, secara umum itu adalah praktik yang buruk. Misalkan saya ingin memanfaatkan fungsi Anda saat menulis sendiri? Ketika saya memanggil metode Anda, metode saya akan membeku. Jika JavaScript entah bagaimana dapat mempertahankan konteks eksekusi fungsi Anda, simpan di suatu tempat, lalu bawa kembali dan lanjutkan kemudian, maka tidur dapat terjadi, tetapi itu pada dasarnya adalah threading.

Jadi, Anda cukup terjebak dengan apa yang disarankan orang lain - Anda harus memecah kode Anda menjadi beberapa fungsi.

Pertanyaan Anda agak salah pilihan, kalau begitu. Tidak ada cara untuk tidur dengan cara yang Anda inginkan, Anda juga tidak harus mengejar solusi yang Anda sarankan.

Ben Flynn
sumber
45
Ini bukan jawaban yang benar sama sekali. Jika Javascript tidak memiliki fungsi tidur, itu hanya karena ECMAScript tidak memerlukannya. Ini adalah pilihan desain oleh tubuh yang bertanggung jawab atas desain Javascript. Bisa saja dibuat bahwa waktu menjalankan Javascript menunggu sejumlah waktu tertentu sebelum menjalankan baris kode berikutnya, tetapi dipilih untuk tidak melakukannya.
Didier A.
5
Tidur dapat diimplementasikan dengan sempurna di JavaScript meskipun tidak dengan ketepatan waktu nyata. Setelah semua itu adalah sistem berbasis acara. Jika panggilan async selesai suatu acara dipicu. Saya tidak melihat alasan mengapa hal yang sama tidak mungkin terjadi ketika sleep () dikeluarkan setelah kontrol dikembalikan ke browser sampai tidur selesai, mengembalikan kontrol ke fungsi panggilan. Dan ya, saya juga setuju bahwa kadang-kadang tidur itu berguna terutama ketika pengembang SEBELUM Anda mengacaukan desain begitu buruk sehingga ANDA tidak memiliki jalan keluar selain benar-benar refactoring yang tidak ada waktu
Lawrence
Coba Hypnotic, yang mengikuti ide ini: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat
4
Memanggil javascript single-threaded hanyalah mitos. Meskipun secara teknis mungkin benar, secara fungsional ia bertindak seperti langauge multithreaded. Mensimulasikan garpu () sepele mudah, dan meskipun yield () tidak benar-benar dapat diterapkan, Anda bisa mendapatkan cukup dekat dengan menggunakan memori bersama untuk mengunci / semafor. Untuk programmer rata-rata, masuk akal untuk memperlakukannya sebagai multi-threaded; nama teknis hanya penting bagi pengembang bahasa.
Benubird
8
Saya setuju mengapa sleep()tidak mungkin di JS, dan sebagian besar waktu ada cara yang lebih baik untuk melakukan sesuatu. Tapi saya masih menganggap cara mesin mengikat semua hal menjadi cacat desain; tidak ada alasan bahasa tidak dapat memiliki sleep()fungsi terbatas pada skrip, halaman, atau fungsi tertentu tanpa mesin menghancurkan CPU dan membekukan aplikasi seperti orang gila. Ini tahun 2015 dan Anda seharusnya tidak dapat merusak seluruh peramban web while(1). Kami memiliki Flash untuk hal-hal seperti itu.
Beejor
660

Dalam JavaScript, saya menulis ulang setiap fungsi sehingga bisa berakhir sesegera mungkin. Anda ingin browser kembali dalam kendali sehingga dapat membuat perubahan DOM Anda.

Setiap kali saya ingin tidur di tengah-tengah fungsi saya, saya refactored untuk menggunakan a setTimeout() .

Edit

Tidur nyenyak, atau menunda, fungsi dalam bahasa apa pun banyak diperdebatkan. Beberapa akan mengatakan bahwa harus selalu ada sinyal atau panggilan balik untuk mengaktifkan fungsionalitas yang diberikan, yang lain akan berpendapat bahwa kadang-kadang momen penundaan yang sewenang-wenang berguna. Saya mengatakan bahwa untuk masing-masing aturan mereka sendiri dan satu tidak pernah bisa mendikte apa pun dalam industri ini.

Menulis fungsi tidur itu sederhana dan menjadikannya lebih bisa digunakan dengan Janji JavaScript:

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

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});
gsamaras
sumber
190
Dengan cara penutupan. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
kekacauan
68
ok, dan bagaimana jika kode tersebut tidak dimaksudkan untuk digunakan di halaman web?
Eugenio Miró
10
@ EugenioMiró jika kode ini tidak dimaksudkan untuk digunakan dalam halaman web, mintalah model objek host menerapkan metode tidur. - Saya pikir pertanyaannya diarahkan ke DOM yang terpapar javascript yang berjalan di halaman web.
BrainSlugs83
31
@Nosredna ya, kami mengerti cara melakukan panggilan async, ini tidak membantu kami tidur (). Saya ingin panggilan saya dibuat dalam urutan tertentu, dan memiliki data kembali dalam urutan tertentu. Saya 5 level dalam untuk loop. Saya ingin eksekusi BLOCK. Metode sleep yang sebenarnya tidak akan "memperlambat browser", kontrol tidur tangan kembali ke browser dan utas lainnya yang menginginkan waktu CPU saat masih memblokir.
BrainSlugs83
382
ini bukan jawaban untuk pertanyaan itu.
TMS
303

Hanya untuk debug / dev , saya memposting ini jika berguna bagi seseorang

Hal menarik, di Firebug (& mungkin konsol js lain), tidak ada yang terjadi setelah menekan enter, hanya setelah durasi tidur yang ditentukan (...)

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

Contoh penggunaan:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }
StephaneAG
sumber
36
Ini bukan jawaban. Persis sama dengan kode dalam pertanyaan, kecuali sedikit lebih pendek.
tusukan
16
Sibuk menunggu, benarkah? Di JS? Selama beberapa detik? Jika saya melihat situs web melakukan ini, itu akan diblokir.
mafu
35
@ mafu Itu sebabnya ia mengatakan only for debug/dev... rolleyes
xDaizu
12
TIDAK PERNAH MELAKUKANNYA. Ini akan membuat CPU mencapai 100% pada inti yang dijalankannya dan akan memblokirnya.
noego
3
Ini berguna, dan mungkin satu-satunya cara untuk tidur, dalam aplikasi javascript command-line, karena async / menunggu tidak membantu.
Wheezil
177

Saya setuju dengan poster yang lain, tidur yang sibuk hanya ide yang buruk.

Namun, setTimeout tidak menahan eksekusi, ia mengeksekusi baris berikutnya dari fungsi segera setelah batas waktu SET, bukan setelah batas waktu berakhir, sehingga tidak menyelesaikan tugas yang sama dengan yang akan dilakukan tidur.

Cara untuk melakukannya adalah dengan memecah fungsi Anda menjadi sebelum dan sesudah bagian.

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

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

Pastikan nama fungsi Anda masih menggambarkan secara akurat apa yang dilakukan masing-masing bagian (IE GatherInputThenWait dan CheckInput, daripada funcPart1 dan funcPart2)

Edit

Metode ini mencapai tujuan untuk tidak mengeksekusi baris kode yang Anda putuskan sampai SETELAH batas waktu Anda, sambil tetap mengembalikan kontrol ke PC klien untuk mengeksekusi apa pun yang telah ia antri.

Edit Lebih Lanjut

Seperti yang ditunjukkan dalam komentar, ini sama sekali TIDAK BEKERJA dalam satu lingkaran. Anda bisa melakukan peretasan (jelek) yang bagus untuk membuatnya bekerja dalam satu lingkaran, tetapi secara umum itu hanya akan membuat kode spageti bencana.

DevinB
sumber
12
Ya. Di mana ini menjadi sulit adalah ketika Anda memiliki loop, atau bahkan loop bersarang. Anda harus mengabaikan loop dan memiliki counter sebagai gantinya.
Nosredna
Sentuh. Maksudku, itu masih mungkin, tapi jelek dan retas dalam kasus itu. Anda juga dapat menggunakan beberapa variabel status boolean statis, tetapi itu juga cukup meretas.
DevinB
2
-1 untuk ini. Sekali lagi, ini tidak menjawab pertanyaan. Ini lebih merupakan jawaban untuk pertanyaan seperti "Cara menjalankan fungsi secara tidak sinkron" yang sangat berbeda dari "Cara memblokir eksekusi kode".
Deepak GM
6
@Nosredna Tidak, Anda akan menggunakan penutupan. Sebagai contoh: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }dan for(var X = 0; X < 3;X++) { foo(X); }- nilai X dilewatkan ke dalam foo, yang kemudian akan digunakan kembali dengan nama indexkapan foo_continueakhirnya dipanggil.
Izkata
2
@Alexander Tentu saja, karena tujuan dari setTimeout () adalah untuk mencegah peramban mengunci dengan menjalankan kode asychronously. Masukkan bagian console.log()dalam ke foo_continue()dalam versi setTimeout dan Anda mendapatkan hasil yang sama.
Izkata
132

Untuk cinta $ DEITY tolong jangan membuat fungsi tidur sibuk-menunggu. setTimeoutdan setIntervallakukan semua yang Anda butuhkan.

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

Setiap dua detik interval sembunyikan teks selama satu detik. Ini menunjukkan cara menggunakan setInterval dan setTimeout untuk menampilkan dan menyembunyikan teks setiap detik.

Philip Rego
sumber
3
Yah tidak semuanya: setInterval melakukan kesan polling yang jauh lebih baik.
annakata
3
Kode apa yang tidak dapat ditahan oleh mesin JavaScript?
Deniz Dogan
10
Kecuali jika Anda perlu tidur agar sinkron, dalam hal ini ini adalah pertanyaan yang sepenuhnya valid.
Aaron Dufour
36
Saya pikir banyak dari kita mungkin lupa bahwa JavaScript bukan bahasa khusus browser. Bung ini mungkin menciptakan utilitas baris perintah Node yang memerlukan jeda singkat tanpa harus berurusan dengan semua masalah pelingkupan variabel yang datang dengan setTimeout.
Phil LaNasa
3
@ PhilLaNasa: Jika penutupan sintaksis masih membuat takut satu, satu serius perlu bekerja keras dan bekerja melalui Node 101.
chaos
113

Saya tahu ini sedikit pertanyaan lama, tetapi jika (seperti saya) Anda menggunakan Javascript dengan Badak, Anda dapat menggunakan ...

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.
   */
}
mjaggard
sumber
4
Apakah ini panggilan ke Jawa?
Ken Sharp
14
Ini Java, bukan Javascript
RousseauAlexandre
18
@RousseauAlexandre Salah. Ini JavaScript menggunakan Badak (pada saat itu, bisa juga menjadi Nashorn hari ini)
mjaggard
71

Jika Anda menggunakan jQuery, seseorang benar-benar membuat plugin "delay" yang tidak lebih dari pembungkus untuk 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;
};

Anda kemudian dapat menggunakannya dalam deretan panggilan fungsi seperti yang diharapkan:

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');
Alan Plum
sumber
4
Itu bukan solusi yang buruk. Menjaga konteks dan keterkaitan.
Nosredna
39
Pada jQuery 1.4, .delay()adalah bagian dari jQuery (meskipun dengan semantik berbeda dari implementasi di atas). api.jquery.com/delay
Matt Ball
7
Apa pertanyaan ini pasti kurang adalah jawaban jQuery . Sangat senang kami mendapatkannya!
xDaizu
1
Jika Anda perlu penundaan antara dua panggilan independen, ya. Jika Anda perlu penundaan untuk memperlambat lingkaran, tidak.
WGroleau
46

Saya telah mencari solusi tidur juga (bukan untuk kode produksi, hanya untuk dev / tes) dan menemukan artikel ini:

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

... dan inilah tautan lain dengan solusi sisi klien: http://www.devcheater.com/

Selain itu, saat Anda menelepon alert(), kode Anda juga akan dijeda, saat peringatan ditampilkan - perlu menemukan cara untuk tidak menampilkan peringatan tetapi mendapatkan efek yang sama. :)

a_w
sumber
35
Saya setuju, banyak orang berkata, "Tidak, jangan lakukan ini dalam kode produksi!" Ya, um, aku tidak mau. Saya ingin melakukannya dalam kode uji sekali pakai, dan sebagai hasilnya saya tidak ingin menghabiskan banyak waktu untuk membuat solusi yang elegan.
user435779
31

Berikut adalah solusi sederhana menggunakan XMLHttpRequest sinkron:

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

isi dari sleep.php:

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

Sebut sekarang dengan: sleep (5);

pguardiario
sumber
5
@ Lukuk, Gunakan setTimeout()jika itu berhasil, tetapi jika melakukannya berarti mengurai 1000 baris panggilan balik ini mungkin mulai tidak terlihat seperti lelucon.
pguardiario
11
Pendekatan unik, meskipun sayangnya XMLHttpRequests non-async sudah usang dan akan dihapus di masa depan. Yang lucu, karena fakta itulah yang mengarahkan saya ke pertanyaan ini.
Beejor
Ini sebenarnya ide yang cukup bagus IMO. Meskipun saya tidak berpikir API tidur (URL Permintaan) harus bersifat publik karena dapat disalahgunakan.
Vahid Amiri
@Beejor selalu berpikir hanya tentang masa depan berarti hidup di masa depan yang tidak realistis :-)
user1742529
bagus tapi tahukah Anda jika terkadang internet lambat atau Waktu ping situs web lebih tinggi daripada script tidur lebih dari waktu argumen. Seperti jika Anda menggunakan sleep(300)dan situs web membutuhkan 150 ms untuk tanggapan daripada kode javascript akan tidur selama 450 ms. dan jika koneksi internet terputus oleh browser, itu akan berfungsi hanya 0ms. Jadi itu bukan solusi yang lebih baik
H Chauhan
30

Ini dia Seperti yang tertulis dalam kode, jangan menjadi pengembang yang buruk dan gunakan ini di situs web. Ini adalah fungsi utilitas pengembangan.

// 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) {}
}
Ian Maddox
sumber
17
Itu pada dasarnya sama dengan yang dimiliki OP.
Andrew Barber
5
Untuk lebih tepatnya, OP meminta ALTERNATIF.
WGroleau
Solusinya tidak bagus, tetapi di beberapa tempat async/awaitsayangnya tidak responsif, dan kita harus menggunakannya secara wajib.
Nabi KAZ
21

Saya pribadi suka yang sederhana:

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

kemudian:

sleep(2); // Sleeps for 2 seconds

Saya menggunakannya sepanjang waktu untuk membuat waktu pemuatan palsu saat membuat skrip dalam P5js

melMass
sumber
3
Saya melihat ini sebagai versi paling optimal dari pertanyaan utama: ia tidak mengerjakan matematika di dalam loop, hanya perbandingan biasa. Agak sulit dibaca.
hegez
4
TIDAK PERNAH MELAKUKANNYA. Sudahkah Anda memeriksa penggunaan CPU saat fungsi ini berfungsi? Itu harus mendekati 100% jika Anda memberikan waktu yang cukup untuk itu.
noego
2
@ Hegez: Mengingat loop akan berjalan untuk jumlah waktu jam dinding tetap tidak peduli apa pun, sepertinya mengoptimalkan loop adalah jenis di samping intinya.
ShadowRanger
@noego Bagaimana bisa begitu? Saya baru saja menguji pada Node 10, saya tidak memiliki perubahan penggunaan CPU sama sekali
melMass
@melMass Fungsi ini hanya memblokir Node thread selama n detik dengan menjaga CPU 100% sibuk. "Solusi" ini adalah ide yang sangat buruk karena dua alasan (memblokir + CPU killer). Menunggu HAS menjadi non-blocking, oleh karena itu tidak sinkron.
Jeremy Thille
20

Pertama:

Tentukan fungsi yang ingin Anda jalankan seperti ini:

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

Kemudian jadwalkan eksekusi dengan metode setTimeout:

setTimeout(alertWorld,1000)

Catat dua hal

  • argumen kedua adalah waktu dalam milidetik
  • sebagai argumen pertama Anda harus memberikan hanya nama (referensi) fungsi, tanpa tanda kurung
Pablo Fernandez
sumber
19

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

pastikan fungsi panggilan Anda async

diverifikasi dan berfungsi dengan baik

Ahmed Mohammedali
sumber
1
Akhirnya. Satu-satunya jawaban.
Jeremy Thille
18

Solusi yang lebih baik untuk membuat segala sesuatu tampak seperti apa yang diinginkan kebanyakan orang adalah dengan menggunakan fungsi anonim:

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

Ini mungkin yang paling dekat Anda akan mendapatkan sesuatu yang hanya melakukan apa yang Anda inginkan.

Catatan, jika Anda membutuhkan beberapa tidur, ini bisa menjadi terburu-buru dan Anda mungkin benar-benar perlu memikirkan kembali desain Anda.

Mainguy
sumber
ini adalah yang bekerja untuk saya di browser desktop dan ponsel yang lebih tua. Yang lain saya coba tidak bekerja sama sekali.
Mike
10

Untuk browser, saya setuju bahwa setTimeout dan setInterval adalah cara yang harus dilakukan.

Tetapi untuk kode sisi server, mungkin memerlukan fungsi pemblokiran (misalnya, agar Anda dapat secara efektif melakukan sinkronisasi utas).

Jika Anda menggunakan node.js dan meteor, Anda mungkin mengalami keterbatasan dalam menggunakan setTimeout di fiber. Berikut adalah kode untuk tidur sisi server.

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

Lihat: https://github.com/laverdet/node-fibers#sleep

Homer6
sumber
Server may require a blocking function... Saya tidak melihat betapa kuatnya memblokir satu-satunya utas Node dan membuat seluruh server Anda tidak responsif selama beberapa detik adalah ide yang bagus, tetapi apa pun
Jeremy Thille
10

Saya akan merangkum setTimeOut dalam Janji untuk konsistensi kode dengan tugas asinkron lainnya: Demo di Fiddle

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

Digunakan seperti itu:

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

Mudah untuk mengingat sintaksis jika Anda menggunakan Janji.

Elo
sumber
4
Mengapa ini lebih baik daripada hanya menggunakan setTimeout (function () {/ * do something * /}, 2000) ;?
JSideris
10

Pembaruan 2019 menggunakan Atomics.wait

Harus bekerja di Node 9.3 atau lebih tinggi.

Saya membutuhkan pengatur waktu yang cukup akurat di Node.js dan itu berfungsi dengan baik untuk itu. Namun sepertinya ada dukungan yang sangat terbatas di browser.

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

Menjalankan beberapa tolok ukur waktu 10 detik.

Dengan setTimeout saya mendapatkan kesalahan hingga 7000 mikrodetik. (7ms)

Dengan Atomics, kesalahan saya tampaknya tetap di bawah 600 mikrodetik. (0,6 ms)

Pembaruan 2020: Dalam Ringkasan

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

dimana halaman sisi server, misalnya sleep.jsp, terlihat seperti

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>
fuweichin
sumber
Menurut pendapat saya lebih baik daripada solusi yang diterima yang tidak dapat diimplementasikan sebagai fungsi sederhana tanpa async / menunggu di pemanggil.
GroovyDotCom
ya, selama Anda sadar bahwa ini menghalangi dan itu biasanya bukan hal yang baik
Kapytanhook
Cukup keren, tetapi fakta bahwa ini hanya benar-benar didukung di Chrome dan Firefox tidak membuatnya sangat layak untuk digunakan di web. (Nov 2019)
JGreatorex
9

Sebagian besar jawaban di sini salah arah atau paling tidak ketinggalan jaman. Tidak ada alasan javascript harus berulir tunggal, dan memang tidak. Hari ini semua browser utama mendukung pekerja, sebelum ini adalah kasus runtime javascript lain seperti Rhino dan Node.js mendukung multithreading.

'Javascript adalah utas tunggal' bukan jawaban yang valid. Misalnya menjalankan fungsi tidur di dalam pekerja tidak akan memblokir kode yang berjalan di utas ui.

Di runtimes yang lebih baru yang mendukung generator dan hasil, seseorang dapat membawa fungsionalitas yang mirip dengan fungsi tidur di lingkungan berulir tunggal:

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

Ini imitasi tidur berbeda dari fungsi tidur yang benar karena tidak menghalangi utas. Ini hanyalah gula di atas fungsi setTimeout javascript saat ini. Jenis fungsi ini telah diterapkan di Task.js dan harus berfungsi hari ini di Firefox.

Gabriel Ratener
sumber
Pekerja tidak diimplementasikan di IE, setidaknya melalui versi 10. Yang saat ini mewakili sejumlah besar pengguna.
Beejor
Benar, itupun tidak praktis untuk diterapkan sleepmenggunakan banyak pekerja. Jika menggunakan fungsi generator Node.js sudah diterapkan dan dapat digunakan seperti yang dijelaskan. Peramban arus utama belum semua generator yang diimplementasikan pada hari ini.
Gabriel Ratener
8

Saya telah mencari / menelusuri beberapa halaman web di javascript sleep / wait ... dan TIDAK ada jawaban jika Anda ingin javascript "RUN, DELAY, RUN" ... apa yang kebanyakan orang dapatkan adalah, "RUN, RUN (tidak berguna) barang), RUN "atau" RUN, RUN + menunda RUN "....

Jadi saya makan burger dan berpikir ::: di sini adalah solusi yang berfungsi ... tetapi Anda harus memotong kode yang sedang berjalan ... ::: ya, saya tahu, ini hanya lebih mudah untuk membaca refactoring .. masih ...

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

// ................. example3:

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

// .............. example4:

<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>
pengguna207408
sumber
5
Oke, ini bekerja dengan setTimeput, tetapi sulit untuk melihat apa yang terjadi. Menggunakan setTimeout sendiri lebih mudah dari ini.
naugtur
7
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}
Shemeer M Ali
sumber
Itu sama dengan pertanyaan sebenarnya. Tidak banyak gunanya menjadikannya jawaban nyata.
EML
2
Bukan solusi yang baik - menggunakan ini di JavaScriptExecutor Selenium menggantung browser Chrome saya sekitar 50% dari waktu pada 2104 MacBook Pro.
Ampelas
7

Solusi terpendek tanpa ketergantungan:

await new Promise(resolve => setTimeout(resolve, 5000));
k06a
sumber
Tidak berfungsi di IE11. Kami mendapatkan kesalahan sintaks untuk fungsi panah.
DDphp
@ Java-DK useawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a
6

Anda tidak dapat tidur seperti itu di JavaScript, atau, lebih tepatnya, Anda tidak boleh tidur. Menjalankan sleep atau loop sementara akan menyebabkan browser pengguna menggantung sampai loop selesai.

Gunakan timer, seperti ditentukan dalam tautan yang Anda referensikan.

Andrew Dunkman
sumber
6

Salah satu skenario di mana Anda mungkin menginginkan fungsi sleep () daripada menggunakan setTimeout () adalah jika Anda memiliki fungsi menanggapi klik pengguna yang pada akhirnya akan membuka jendela baru yaitu jendela popup dan Anda telah memulai beberapa pemrosesan yang memerlukan periode singkat untuk menyelesaikan sebelum popup ditampilkan. Memindahkan jendela yang terbuka menjadi penutup berarti jendela itu biasanya diblokir oleh browser.

kejujuran
sumber
6

Saya dapat memahami tujuan fungsi tidur jika Anda harus berurusan dengan eksekusi yang sinkron. Fungsi setInterval dan setTimeout membuat utas eksekusi paralel yang mengembalikan urutan eksekusi kembali ke program utama, yang tidak efektif jika Anda harus menunggu hasil yang diberikan. Tentu saja seseorang dapat menggunakan acara dan penangan, tetapi dalam beberapa kasus bukan itu yang dimaksudkan.

naazgull
sumber
6

Menambahkan dua bit saya. Saya perlu menunggu-tunggu untuk keperluan pengujian. Saya tidak ingin membagi kode karena itu akan banyak pekerjaan, jadi sederhana untuk melakukannya untuk saya.

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

Saya tidak melihat kelemahan dalam melakukan ini dan itu berhasil bagi saya.

caiocpricci2
sumber
Itu mungkin dikompilasi.
Viktor Sehr
Tolong jangan lakukan ini dengan cara ini. Ini adalah panggilan tidur pemblokiran , yang berarti tidak ada javascript lain yang dapat berjalan saat kode Anda memonopoli thread JS.
Steve Midgley
5
@SteveMidgley "tidak ada javascript lain [yang dapat] berjalan saat kode Anda memonopoli JS thread" menurut saya tepat seperti yang ingin dilakukan OP: __ (ツ) _ / ¯
drigoangelo
1
Saya baru saja menjalankan beberapa tes dan tampaknya bahkan loop kosong akan memblokir browser dan CPU (bukan hanya JavaScript). Dan menggunakan forloop hampir selalu akan segera dieksekusi, terlepas dari nilai maks untuk i, dan bahkan dengan kode matematika yang rumit ditempatkan di dalamnya. Jadi, kecuali Anda hanya menunggu beberapa milidetik, tampaknya masih tidak ada cara untuk tidur dengan anggun di JS.
Beejor
1 juta terlalu besar. Bagi saya cukup 10k
Vlad
6

Ini dapat dilakukan dengan menggunakan metode tidur Java. Saya sudah mengujinya di FF dan IE dan tidak mengunci komputer, mengunyah sumber daya, atau menyebabkan hit server tanpa akhir. Sepertinya solusi bersih bagi saya.

Pertama, Anda harus mendapatkan Java dimuat pada halaman dan membuat metodenya tersedia. Untuk melakukan itu, saya melakukan ini:

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

Kemudian, yang harus Anda lakukan ketika Anda ingin jeda tanpa rasa sakit di JS Anda adalah:

java.lang.Thread.sleep(xxx)

Di mana xxx adalah waktu dalam milidetik. Dalam kasus saya (dengan alasan pembenaran), ini adalah bagian dari pemenuhan pesanan back-end di perusahaan yang sangat kecil dan saya perlu mencetak faktur yang harus dimuat dari server. Saya melakukannya dengan memuat faktur (sebagai halaman web) ke dalam iFrame dan kemudian mencetak iFrame. Tentu saja, saya harus menunggu sampai halaman dimuat sepenuhnya sebelum saya bisa mencetak, sehingga JS harus berhenti. Saya menyelesaikan ini dengan memiliki halaman faktur (di iFrame) mengubah bidang formulir tersembunyi pada halaman induk dengan acara onLoad. Dan kode pada halaman induk untuk mencetak faktur tampak seperti ini (bagian yang tidak relevan dipotong untuk kejelasan):

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

Jadi pengguna menekan tombol, skrip memuat halaman faktur, lalu menunggu, memeriksa setiap seperempat detik untuk melihat apakah halaman faktur selesai memuat, lalu muncul dialog cetak agar pengguna mengirimnya ke printer. QED.

Rachael
sumber
12
Tampaknya soulution cukup mengerikan ketika mempertimbangkan hal sederhana yang ingin dicapai penulis.
xaralis
2
Ini tergantung pada Java Applet yang sudah usang.
Vahid Amiri
6

Banyak jawaban tidak (langsung) menjawab pertanyaan, dan begitu juga yang ini ...

Inilah dua sen (atau fungsi) saya:

Jika Anda ingin fungsi yang kurang kikuk daripada setTimeoutdan setInterval, Anda bisa membungkusnya dalam fungsi yang hanya membalik urutan argumen dan memberi mereka nama yang bagus:

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

Versi CoffeeScript:

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

Anda kemudian dapat menggunakannya dengan baik dengan fungsi anonim:

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

Sekarang terbaca dengan mudah sebagai "setelah N milidetik, ..." (atau "setiap N milidetik, ...")

1j01
sumber
5

Untuk kasus tertentu yang ingin menghilangkan ruang panggilan yang dieksekusi oleh loop, Anda dapat menggunakan sesuatu seperti kode di bawah ini dengan prototipe. Tanpa prototipe, Anda dapat mengganti fungsi penundaan dengan 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)
}
beauburrier
sumber
5

Jika Anda menggunakan node.js, Anda dapat melihat serat - ekstensi C asli ke simpul, simulasi yang agak multi-threading.

Hal ini memungkinkan Anda untuk melakukan yang nyata sleepdengan cara yang memblokir eksekusi dalam serat, tetapi tidak menghalangi di utas utama dan serat lainnya.

Berikut adalah contoh baru dari readme mereka sendiri:

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

- dan hasilnya adalah:

$ 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)
Tomekwi
sumber