Подождите 5 секунд перед выполнением следующей строки

313

Эта функция ниже не работает так, как я хочу; будучи новичком JS, я не могу понять, почему.

Мне нужно подождать 5 секунд, прежде чем проверять, newStateесть ли -1.

В настоящее время он не ждет, он просто проверяет сразу.

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

  if(newState == -1) {
    alert('VIDEO HAS STOPPED');
  }
}
copyflake
источник

Ответы:

323

Вы должны поместить свой код в функцию обратного вызова, которую вы предоставляете setTimeout:

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

Любой другой код будет выполнен немедленно.

Джозеф Силбер
источник
4
Основная проблема заключается в том, что в некоторых случаях (особенно при тестировании) это крайне неадекватно. Что если вам нужно поспать 500 мс, прежде чем вернуться из функции, например, для имитации медленного асинхронного http-запроса?
А.Грандт
14
Если под «тестированием» вы подразумеваете модульные тесты: ваша тестовая среда должна иметь возможность запускать асинхронные тесты. Если вы имеете в виду ручное тестирование: на вкладке «Сеть» в Chrome есть раскрывающийся список «Регулирование» для имитации медленных запросов.
Джозеф Сильбер
1
что если я разработаю расширение chrome, и последнее оцененное значение во вставленном скрипте должно дать мне результат; а мне нужны задержки?
Mirek
184

Вы действительно не должны этого делать , правильное использование тайм-аута является подходящим инструментом для решения проблемы ОП и любого другого случая, когда вы просто хотите запустить что-то через определенный промежуток времени. Джозеф Силбер хорошо показал это в своем ответе. Однако, если в каком-то непроизводственном случае вы действительно хотите повесить основной поток на некоторое время, это будет сделано.

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

С исполнением в виде:

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

Я приехал сюда, потому что я создавал простой тестовый пример для упорядочения сочетания асинхронных операций вокруг длительных операций блокировки (т. Е. Дорогостоящей манипуляции с DOM), и это моя операция имитации блокировки. Это хорошо подходит для этой работы, поэтому я решил опубликовать ее для всех, кто прибывает сюда с аналогичным сценарием использования. Тем не менее, он создает объект Date () в цикле while, который может сильно перегружать GC, если он выполняется достаточно долго. Но я не могу особо подчеркнуть, это подходит только для тестирования, для создания любой реальной функциональности вы должны обратиться к ответу Джозефа Силбера.

микрофон
источник
7
Это не остановит выполнение JavaScript.
Терри Лин
23
@TerryLin Попробуйте запустить его.
Mic
6
В общем, вы тратите время процессора. Это не ожидание, поскольку вы не переводите поток в спящий режим, позволяя главному процессору сосредоточиться на других задачах.
Kyordhel
6
@Gzork Поток сна - это только один из способов реализации функции ожидания, и он, к сожалению, недоступен в контексте клиентского JavaScript. Однако, если вы думаете, что другие асинхронные задачи в клиенте будут выполнены во время его работы, то вы, очевидно, не проверяли его. Хотя я бы использовал его в основном потоке, я собрал скрипку, иллюстрирующую, как, даже если она вызывается через setTimeout, она все равно прерывает другие асинхронные события jsfiddle.net/souv51v3/1 - вы найдете даже Само окно JSFiddle перестает отвечать на запросы во время его завершения.
Мик
1
Ужасное решение ИМХО - перегружает процессор, пока он «спит». Правильный способ засыпания - это асинхронный / ожидающий ответ на этот вопрос stackoverflow.com/questions/951021/… или ответ Этьена.
Дэвид Симик
164

Вот решение с использованием нового синтаксиса async / await .

Обязательно проверьте поддержку браузера, так как это новая функция, представленная в ECMAScript 6.

Вспомогательная функция:

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

Использование:

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

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

Преимущество этого подхода в том, что он делает ваш код похожим на синхронный код.

Этьен Мартин
источник
Не нужно ECMAScript 6: Если вы уже используете обещания для асинхронной загрузки и просто хотите имитировать одну часть цепочки, занимающую много времени, вы можете добавить эту функцию wait () в цепочку.
Довев Хефец
2
Это действительно лучший ответ с новым синтаксисом. У меня были проблемы с использованием решения wait () выше.
pianoman102
36

Вы не должны просто пытаться сделать паузу в 5 секунд в JavaScript. Это не работает таким образом. Вы можете запланировать выполнение функции кода через 5 секунд, но вы должны поместить код, который вы хотите запустить позже, в функцию, а остальная часть кода после этой функции продолжит работать немедленно.

Например:

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

Но если у вас есть такой код:

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

console.log()Заявление будет работать сразу. Он не будет ждать, пока не истечет время ожидания в stateChange()функции. Вы не можете просто приостановить выполнение JavaScript на заранее установленное время.

Вместо этого любой код, который вы хотите запустить с задержками, должен быть внутри setTimeout()функции обратного вызова (или вызываться из этой функции).

Если вы попытаетесь «сделать паузу» зацикливанием, то вы по существу «повесите» интерпретатор Javascript на некоторое время. Поскольку Javascript запускает ваш код только в одном потоке, когда вы зацикливаетесь, ничто другое не может выполняться (никакие другие обработчики событий не могут быть вызваны). Таким образом, циклическое ожидание изменения какой-либо переменной никогда не будет работать, потому что никакой другой код не может быть запущен для изменения этой переменной.

jfriend00
источник
31
Вы не можете просто приостановить выполнение JavaScript на заранее установленное время . Я думаю, что вы имеете в виду, что вы не должны, так как вы можете (если вы хотите повеситься):var t = new Date().getTime(); while (new Date().getTime() < t + millisecondsToLockupBrowser);
Джозеф Силбер
9
@JosephSilber - Ладно, хорошо, вы могли бы сделать это, но на практике это не работает, так как многие браузеры выдают диалоговое окно, в котором говорится, что скрипт перестал отвечать на запросы, и это ужасно для пользователя, и это плохо для батареи и страницы повесил при этом и ... это было бы плохо.
jfriend00
12
Ну, конечно, это было бы ужасно, и никто никогда не должен когда-либо когда-либо когда-либо делать это. Я просто не мог устоять перед своим внутренним "хорошо на самом деле" . Сожалею.
Джозеф Сильбер
31

Если вы находитесь в асинхронной функции, вы можете просто сделать это в одной строке:

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

Обратите внимание , что если целью является NodeJS, будет более эффективно использовать это (это предопределенная обещанная функция setTimeout):

await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000) // 3 sec
ЗЫ
источник
В чем разница между двумя реализациями?
EAzevedo
1
В настоящее время разницы нет. Но если в какой-то момент узел решит сделать его быстрее / безопаснее / эффективнее, вы будете использовать версию узла js заранее. Хотя читабельность, скорее всего, будет ключевым фактором для большинства людей, и в этом случае вам лучше использовать первый способ.
ЗЫ
Спасибо. Ваш ответ решил проблему, с которой я столкнулся уже три дня. Спасибо.
EAzevedo
8

Попробуй это:

//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);
    }
}
Стив Цзян
источник
7

Лучший способ создать такую ​​функцию для ожидания в миллисекундах, эта функция будет ожидать миллисекунды, указанные в аргументе:

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

Джитендра Пал - JP
источник
3

Основываясь на ответе Джозефа Силбера , я бы сделал это немного более обобщенно.

Вы бы получили свою функцию (давайте создадим ее на основе вопроса):

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

И вы могли бы иметь функцию ожидания:

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

В конце у вас будет:

wait(5000, videoStopped, newState);

Это решение, я бы предпочел не использовать аргументы в функции ожидания (чтобы иметь только foo();вместо foo(arg);), но это для примера.

Sylhare
источник
1

Вы можете добавить задержку, внеся небольшие изменения в вашу функцию (async и await).

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();
п.дурга Шанкар
источник
-2

используя angularjs:

$timeout(function(){
if(yourvariable===-1){
doSomeThingAfter5Seconds();
}
},5000)
Доктор аббос
источник
-2

Создать новую функцию Js

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

Вызывайте функцию, если вы хотите отложить выполнение. Используйте миллисекунды в int для значения задержки.

####Some code
 sleep(1000);
####Next line
Мадушанка Сампат
источник
3
Это будет потреблять слишком много ресурсов.
Авави
-2

Я использовал его для запуска компьютерных игр от края или IE. И он самозакрывается IE Edge через 7 секунд.

Firefox и Google Chrome не могут быть использованы для запуска игр таким образом.

<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>
user4565320
источник