Tunggu 5 detik sebelum menjalankan baris berikutnya

313

Fungsi di bawah ini tidak berfungsi seperti yang saya inginkan; menjadi pemula JS saya tidak tahu mengapa.

Saya perlu menunggu 5 detik sebelum memeriksa apakah newStateis -1.

Saat ini, tidak menunggu, hanya memeriksa langsung.

function stateChange(newState) {
  setTimeout('', 5000);

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}
copyflake
sumber

Jawaban:

323

Anda harus memasukkan kode Anda dalam fungsi panggilan balik yang Anda berikan ke setTimeout:

function stateChange(newState) {
    setTimeout(function () {
        if (newState == -1) {
            alert('VIDEO HAS STOPPED');
        }
    }, 5000);
}

Kode lain akan segera dieksekusi.

Joseph Silber
sumber
4
Masalah utama adalah bahwa dalam beberapa kasus (pengujian khusus) ini sangat tidak memadai. Bagaimana jika Anda perlu tidur selama 500 ms sebelum kembali dari fungsi, misalnya untuk mensimulasikan permintaan http async yang lambat ?
A.Grandt
14
Jika dengan "menguji" yang Anda maksud pengujian unit: kerangka pengujian Anda harus memiliki cara untuk menjalankan tes async. Jika yang Anda maksud pengujian manual: Tab Jaringan Chrome memiliki tarik turun Throttling untuk mensimulasikan permintaan lambat.
Joseph Silber
1
bagaimana jika saya mengembangkan ekstensi chrome dan nilai terakhir yang dievaluasi dalam skrip yang disuntikkan akan memberi saya hasilnya; dan saya perlu penundaan?
mirek
184

Anda benar-benar tidak boleh melakukan ini , penggunaan batas waktu yang tepat adalah alat yang tepat untuk masalah OP dan setiap kesempatan lain di mana Anda hanya ingin menjalankan sesuatu setelah jangka waktu tertentu. Joseph Silber telah menunjukkan hal itu dengan baik dalam jawabannya. Namun, jika dalam beberapa kasus non-produksi Anda benar - benar ingin menggantung utas utama untuk jangka waktu tertentu, ini akan berhasil.

function wait(ms){
   var start = new Date().getTime();
   var end = start;
   while(end < start + ms) {
     end = new Date().getTime();
  }
}

Dengan eksekusi dalam bentuk:

console.log('before');
wait(7000);  //7 seconds in milliseconds
console.log('after');

Saya telah tiba di sini karena saya sedang membangun test case sederhana untuk mengurutkan campuran operasi asinkron di sekitar operasi pemblokiran yang berjalan lama (yaitu manipulasi DOM yang mahal) dan ini adalah operasi pemblokiran yang disimulasikan. Ini cocok dengan pekerjaan itu, jadi saya pikir saya mempostingnya untuk orang lain yang datang ke sini dengan menggunakan case yang serupa. Meski begitu, itu membuat objek Date () dalam loop sementara, yang mungkin sangat membebani GC jika berjalan cukup lama. Tapi saya tidak bisa cukup menekankan, ini hanya cocok untuk pengujian, untuk membangun fungsionalitas aktual yang Anda harus merujuk pada jawaban Joseph Silber.

Mik
sumber
7
Ini tidak akan menghentikan eksekusi javascript.
Terry Lin
23
@TerryLin Coba jalankan.
Mic
6
Jadi pada dasarnya Anda membuang-buang waktu CPU. Itu bukan menunggu karena Anda tidak menempatkan utas ke mode tidur yang memungkinkan prosesor utama untuk fokus dalam tugas-tugas lain.
Kyordhel
6
@Gzork Thread sleep hanya satu cara untuk mengimplementasikan fungsi menunggu, dan sayangnya tidak tersedia dalam konteks javascript sisi klien. Namun, jika Anda berpikir tugas asinkron lain di klien akan selesai saat sedang berjalan, maka Anda jelas belum mengujinya. Meskipun saya akan menggunakannya di utas utama, saya mengumpulkan biola yang mengilustrasikan bagaimana bahkan jika ini disebut melalui setTimeout di tempat pertama, itu masih mengganggu acara async lainnya jsfiddle.net/souv51v3/1 - Anda akan menemukan bahkan Jendela JSFiddle sendiri menjadi tidak responsif saat selesai.
Mik
1
IMHO solusi mengerikan - babi CPU saat itu "tidur." Cara yang tepat untuk tidur adalah melalui async / tunggu ala jawaban ini stackoverflow.com/questions/951021/… atau Etienne's.
David Simic
163

Inilah solusi menggunakan sintaks async / await baru .

Pastikan untuk memeriksa dukungan browser karena ini adalah fitur baru yang diperkenalkan dengan ECMAScript 6.

Fungsi utilitas:

const delay = ms => new Promise(res => setTimeout(res, ms));

Pemakaian:

const yourFunction = async () => {
  await delay(5000);
  console.log("Waited 5s");

  await delay(5000);
  console.log("Waited an additional 5s");
};

Keuntungan dari pendekatan ini adalah membuat kode Anda terlihat dan berperilaku seperti kode sinkron.

Etienne Martin
sumber
Tidak perlu ECMAScript 6: Jika Anda sudah menggunakan janji untuk melakukan pemuatan async dan hanya ingin meniru satu bagian dari rantai yang membutuhkan waktu lama, Anda dapat menambahkan fungsi wait () ini ke rantai.
Dovev Hefetz
2
Ini benar-benar jawaban terbaik dengan sintaks baru. Saya punya masalah dengan menggunakan solusi wait () di atas.
pianoman102
36

Anda seharusnya tidak hanya mencoba menjeda 5 detik dalam javascript. Tidak berfungsi seperti itu. Anda dapat menjadwalkan fungsi kode untuk menjalankan 5 detik dari sekarang, tetapi Anda harus memasukkan kode yang ingin Anda jalankan nanti ke dalam suatu fungsi dan sisa kode Anda setelah fungsi itu akan terus berjalan segera.

Sebagai contoh:

function stateChange(newState) {
    setTimeout(function(){
        if(newState == -1){alert('VIDEO HAS STOPPED');}
    }, 5000);
}

Tetapi, jika Anda memiliki kode seperti ini:

stateChange(-1);
console.log("Hello");

The console.log()pernyataan akan segera berjalan. Ini tidak akan menunggu sampai setelah batas waktu menyala dalam stateChange()fungsi. Anda tidak bisa hanya menghentikan sementara eksekusi javascript untuk jumlah waktu yang telah ditentukan.

Sebaliknya, kode apa pun yang Anda ingin tunda harus berada di dalam setTimeout()fungsi panggilan balik (atau dipanggil dari fungsi itu).

Jika Anda memang mencoba "berhenti" dengan mengulang, maka Anda pada dasarnya akan "menggantung" penerjemah Javascript untuk jangka waktu tertentu. Karena Javascript menjalankan kode Anda hanya dalam satu utas, ketika Anda mengulang, tidak ada lagi yang dapat dijalankan (tidak ada penangan acara lainnya yang dapat dipanggil). Jadi, pengulangan menunggu beberapa variabel untuk berubah tidak akan berfungsi karena tidak ada kode lain yang dapat dijalankan untuk mengubah variabel itu.

pacar00
sumber
31
Anda tidak bisa hanya menghentikan sementara eksekusi javascript untuk jumlah waktu yang telah ditentukan . Saya pikir Anda maksud Anda tidak boleh, karena Anda bisa (jika Anda ingin gantung diri):var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Joseph Silber
9
@JosephSilber - OK baik-baik saja, Anda bisa melakukan itu, tetapi dalam praktiknya itu tidak berfungsi karena banyak browser akan membuat dialog yang mengatakan bahwa skrip telah menjadi tidak responsif DAN itu adalah pengalaman pengguna yang mengerikan dan buruk untuk masa pakai baterai dan halaman tersebut digantung saat melakukan itu dan ... Itu akan buruk.
jfriend00
12
Ya tentu saja itu akan mengerikan, dan tidak ada yang pernah bisa melakukan itu. Saya hanya tidak bisa menolak batin saya "sebenarnya-baik" . Maaf.
Joseph Silber
31

Jika Anda berada dalam fungsi async, Anda cukup melakukannya dalam satu baris:

console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);

Perhatikan , jika target adalah NodeJS akan lebih efisien untuk menggunakan ini (ini adalah fungsi setTimeout yang telah ditentukan sebelumnya):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec
Shl
sumber
Apa perbedaan antara kedua implementasi?
EAzevedo
1
Saat ini, tidak ada perbedaan. Tetapi jika pada titik tertentu simpul akan memutuskan untuk membuatnya lebih cepat / lebih aman / lebih efisien Anda akan menggunakan versi muka node js. Meskipun keterbacaan lebih cenderung menjadi faktor kunci bagi kebanyakan orang, dalam hal ini Anda lebih baik menggunakan cara pertama.
Shl
Terima kasih. Jawaban Anda memecahkan masalah yang telah saya hadapi selama tiga hari. Terima kasih.
EAzevedo
8

Coba ini:

//the code will execute in 1 3 5 7 9 seconds later
function exec() {
    for(var i=0;i<5;i++) {
        setTimeout(function() {
            console.log(new Date());   //It's you code
        },(i+i+1)*1000);
    }
}
Steve Jiang
sumber
7

Cara terbaik untuk membuat fungsi seperti ini untuk menunggu dalam mili detik, fungsi ini akan menunggu selama milidetik yang disediakan dalam argumen:

function waitSeconds(iMilliSeconds) {
    var counter= 0
        , start = new Date().getTime()
        , end = 0;
    while (counter < iMilliSeconds) {
        end = new Date().getTime();
        counter = end - start;
    }
}

Jitendra Pal - JP
sumber
3

Berdasarkan jawaban Joseph Silber , saya akan melakukannya seperti itu, sedikit lebih generik.

Anda akan memiliki fungsi Anda (mari kita buat berdasarkan pertanyaan):

function videoStopped(newState){
   if (newState == -1) {
       alert('VIDEO HAS STOPPED');
   }
}

Dan Anda bisa memiliki fungsi menunggu:

function wait(milliseconds, foo, arg){
    setTimeout(function () {
        foo(arg); // will be executed after the specified time
    }, milliseconds);
}

Pada akhirnya Anda akan memiliki:

wait(5000, videoStopped, newState);

Itu solusinya, saya lebih suka tidak menggunakan argumen dalam fungsi menunggu (hanya untuk memiliki foo();bukan foo(arg);) tapi itu misalnya.

Sylhare
sumber
3

Solusi ini berasal dari dokumentasi React Native untuk kontrol penyegaran :

function wait(timeout) {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

Untuk menerapkan ini pada pertanyaan OP, Anda dapat menggunakan fungsi ini dalam koordinasi dengan await:

await wait(5000);
if (newState == -1) {
    alert('Done');
}
bearacuda13
sumber
1

Anda dapat menambahkan penundaan dengan membuat perubahan kecil pada fungsi Anda (async dan menunggu).

const add5SecondsDelay = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('5 seconds');
    }, 50000);
  });
}

async function asyncFunctionCall() {

  console.log("stpe-1"); 
  const result = await add5SecondsDelay ();
  console.log("step-2 after 5 seconds delay"); 

}

asyncFunctionCall();
p.urga shankar
sumber
-2

menggunakan angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)
Abbos
sumber
-2

Buat fungsi Js baru

function sleep(delay) {
        var start = new Date().getTime();
        while (new Date().getTime() < start + delay);
      }

Panggil fungsi ketika Anda ingin menunda eksekusi. Gunakan milidetik di int untuk nilai penundaan.

####Some code
 sleep(1000);
####Next line
Madushanka Sampath
sumber
3
Itu akan menghabiskan terlalu banyak sumber daya.
awavi
-2

Saya menggunakannya untuk menjalankan game PC dari edge atau IE. Dan itu menutup IE Edge setelah 7 detik.

Firefox dan Google Chrome tidak dapat digunakan untuk memulai permainan dengan cara ini.

<html<body>
<a href="E:\game\game.exe" name="game" onmouseout="waitclose(7000);"> game
<img src="game.jpg" width="100%" height="97%" ></a>
<script>
function waitclose(ms){
 var start = new Date().getTime();var end=start;
 while(end < start + ms) {end = new Date().getTime();}
window.open('', '_self', ''); window.close();
}
</script>
</body></html>
pengguna4565320
sumber