Зачекайте 5 секунд, перш ніж виконати наступний рядок


313

Ця функція нижче не працює так, як я цього хочу. будучи початківцем JS, я не можу зрозуміти, чому.

Мені потрібно почекати 5 секунд, перш ніж перевірити, чи newStateє -1.

Наразі він не чекає, він просто перевіряє.

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

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

Відповіді:


323

Ви повинні ввести свій код у функцію зворотного дзвінка, яку ви постачаєте setTimeout:

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

Будь-який інший код буде виконаний негайно.


4
Основна проблема полягає в тому, що в деяких випадках (конкретно тестування) це надзвичайно неадекватно. Що робити, якщо вам потрібно спати 500 мс, перш ніж повернутися з функції, наприклад, щоб імітувати повільний запит асинхронізації http?
А.Грандт

14
Якщо під "тестуванням" ви маєте на увазі одиничні тести: ваш тестовий фреймворк повинен мати спосіб запускати асинхронні тести. Якщо ви маєте на увазі тестування вручну: на вкладці Мережа Chrome є спадне меню Throttling для імітації повільних запитів.
Джозеф Сільбер

1
що, якщо я розробимо хромове розширення, і останнє оцінене значення у введеному сценарії повинно дати мені результат; і мені потрібні певні затримки?
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 () в циклі часу, який може дуже переповнити GC, якщо він працює досить довго. Але я не можу наголосити достатньо, це підходить лише для тестування, для побудови будь-якої фактичної функціональності, на яку слід звернутися до відповіді Джозефа Сілбера.


7
Це не зупинить виконання JavaScript.
Террі Лін

23
@TerryLin Спробуйте запустити його.
Мік

6
Таким чином, ви в основному витрачаєте час на процесор. Це не чекання, оскільки ви не вводите нитку в сплячий режим, що дозволяє основного процесору зосередитися на інших завданнях.
Кіордхель

6
Сон @Gzork Thread - це лише один із способів реалізувати функцію очікування, і вона, на жаль, недоступна в контексті JavaScript на стороні клієнта. Однак якщо ви думаєте, що інші асинхронні завдання клієнта будуть виконані під час роботи, ви, очевидно, ще не перевірили його. Хоча я використовував би його в основному потоці, я зібрав загадку, що ілюструє, як навіть якщо це викликається в першу чергу через setTimeout, воно все одно перериває інші події асинхронії jsfiddle.net/souv51v3/1 - ви знайдете навіть Сам вікно JSFiddle стає невідповідним під час його заповнення.
Мік

1
Жахливе рішення IMHO - свинячий процесор, поки він "спить". Правильний спосіб сну - це через async / очікувати аля цієї відповіді stackoverflow.com/questions/951021/… або Етьєна.
Девід Сіміч

162

Ось рішення з використанням нового синтаксису асинхрон / очікування .

Не забудьте перевірити підтримку браузера, оскільки це нова функція, представлена ​​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 запускає ваш код лише в один потік, під час циклу нічого іншого не може працювати (жоден інший обробник подій не може викликати). Отже, циклічне очікування зміни певної змінної ніколи не працюватиме, оскільки жоден інший код не може працювати для зміни цієї змінної.


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
В даний час різниці немає. Але якщо в якийсь момент вузол вирішить зробити його швидшим / безпечнішим / ефективнішим, ви будете використовувати версію node 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;
    }
}


3

Грунтуючись на Джозефа Silber в відповідь , я хотів би зробити це так, трохи більш універсальним.

У вас є ваша функція (давайте створимо її на основі запитання):

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);), але це для прикладу.


3

Це рішення походить з документації React Native для контролю оновлення :

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

Щоб застосувати це до питання щодо ОП, ви можете використовувати цю функцію в координації з await:

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

1

Ви можете додати затримку, внісши невеликі зміни у свою функцію (асинхронізуйте і очікуйте).

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

Створіть нову функцію Js

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

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

####Some code
 sleep(1000);
####Next line

3
Це зажадає занадто багато ресурсів.
awavi

-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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.