Что такое JavaScript-версия sleep ()?


2339

Есть ли лучший способ создать sleepв JavaScript, чем следующая pausecompфункция ( взято здесь )?

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

Это не дубликат Sleep в JavaScript - задержка между действиями ; Мне нужен настоящий сон в середине функции, а не задержка перед выполнением фрагмента кода.


4
Это должно быть установлено в середине времени, если я использую setTimeout, то while будет продолжать обрабатывать и ставить в очередь больше setTimeouts, которые в конечном итоге будут выполняться одновременно и создавать некоторый параллелизм между ними
fmsf

160
Это ужасное решение - вы будете жевать циклы обработки, ничего не делая.
17 из 26

12
Единственная цель для сна - опрос или ожидание обратного вызова - setInterval и setTimeout работают лучше, чем этот.
Аннаката

1
Вероятно, вы можете делать то, что вы хотите с продолжением передачи стиля в JavaScript. Посмотрите на эту статью.
Огнян Димитров

Ответы:


2566

2017 - 2019 обновление

С 2009 года, когда был задан этот вопрос, JavaScript значительно эволюционировал. Все остальные ответы сейчас устарели или слишком сложны. Вот текущая лучшая практика:

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

Это оно. await sleep(<duration>),

Или как однострочник:

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

Обратите внимание, что,

  1. awaitможет выполняться только в функциях с префиксом asyncключевого слова или на верхнем уровне вашего сценария в некоторых средах (например, консоль Chrome DevTools или Runkit).
  2. awaitтолько приостанавливает текущую asyncфункцию

Две новые функции JavaScript помогли написать эту «спящую» функцию:

Совместимость

Если по какой-то странной причине вы используете Node старше 7 лет ( срок действия которого истек ) или нацелены на старые браузеры, то async/ awaitвсе еще можно использовать через Babel (инструмент, который перенесет JavaScript + новые функции в обычный старый JavaScript) , с transform-async-to-generatorплагином.


5
Отличный материал здесь. Интересно, как это влияет или связано с «активными» / «неактивными» состояниями современных браузеров после того, как JS вызывает «спящий» режим? Может ли браузер блокировать спящий режим, как и ожидалось для обычного JS, чтобы позже вызывать его, когда он становится «активным», или у него другое поведение?
Андре Канильо

18
Какова текущая поддержка браузера для этого? Я бы не считал предыдущие решения «устаревшими», пока это решение не поддерживается подавляющим большинством браузеров или, по крайней мере, всеми распространенными. Наоборот, я бы посчитал это решение интересным, но непригодным / непрактичным, пока оно не получит широкую поддержку.
Элвин Томпсон

75
Это не «настоящий сон» и не отвечает на вопрос. Человек, который спросил, четко определил различие между stackoverflow.com/questions/758688/sleep-in-javascript и его вопросом. В реальном сне никакой другой код не может быть выполнен (кроме как в другом потоке). Этот ответ хорош для другого вопроса.
niry

4
@jacroe - транспортер обрабатывает функции стрелок, а также выполняет асинхронное / ожидание (что в любом случае вызывает рвоту в IE)
Jaromanda X

11
@niry JavaScript, будучи однопоточным языком, не очень подходит для «реального» сна, так как он работает в том же потоке, что и пользовательский интерфейс, и может вызвать не отвечающие веб-страницы.
Патрик Робертс

849

(См. Обновленный ответ за 2016 год )

Я думаю, что вполне разумно хотеть выполнить действие, подождать, а затем выполнить другое действие. Если вы привыкли писать на многопоточных языках, у вас, вероятно, есть идея дать выполнение за определенное время, пока ваш поток не проснется.

Проблема здесь заключается в том, что JavaScript является однопоточной моделью, основанной на событиях. Хотя в конкретном случае было бы неплохо подождать всего несколько секунд, но в целом это плохая практика. Предположим, я хотел использовать ваши функции, когда писал свои собственные? Когда я вызывал твой метод, все мои методы зависали. Если JavaScript может каким-то образом сохранить контекст выполнения вашей функции, сохранить его где-нибудь, затем вернуть обратно и продолжить позже, тогда может произойти сон, но это в основном будет потоковым.

Таким образом, вы в значительной степени застряли на том, что предложили другие - вам нужно разбить ваш код на несколько функций.

Тогда ваш вопрос немного ошибочен. Нельзя спать так, как вы хотите, и вы не должны следовать предложенному вами решению.


45
Это не правильный ответ вообще. Если Javascript не имеет функции сна, это только потому, что ECMAScript не требует этого. Это выбор дизайна органом, ответственным за дизайн Javascript. Можно было бы сделать так, чтобы время выполнения Javascript ожидало заданное количество времени перед запуском следующей строки кода, но было решено не делать этого.
Дидье А.

5
Сон может быть прекрасно реализован в JavaScript, но не с точностью в реальном времени. Ведь это система событий. Если асинхронные вызовы завершены, происходит событие. Я не вижу причин, почему то же самое не может быть возможным, когда выдается sleep (), после которого управление возвращается браузеру до тех пор, пока оно не закончится, возвращая управление вызывающей функции. И да, я также согласен, что иногда спать удобно, особенно когда разработчики ДО того, как вы испортили дизайн так сильно, что у вас нет другого выхода, кроме полного рефакторинга, на который у вас нет времени
Лоуренс,

Попробуйте Hypnotic, которая следует этой идее: coolwanglu.github.io/hypnotic/web/demo.html
Tezcat

4
Называть JavaScript однопоточным - это миф. Хотя это может быть технически правильным, функционально он действует как многопоточный язык. Имитация fork () тривиально проста, и хотя yield () на самом деле нереализуем, но вы можете приблизиться к нему, используя разделяемую память для блокировки / семафора. Для среднего программиста имеет смысл рассматривать его как многопоточный; техническое название имеет значение только для разработчиков языка.
Benubird

8
Я согласен, почему sleep()в JS это невозможно, и что в большинстве случаев есть лучшие способы сделать что-то. Но я все еще рассматриваю способ, которым двигатель связывает все вещи, чтобы быть недостатком дизайна; нет причины, по которой язык не может иметь sleep()функцию, ограниченную конкретным сценарием, страницей или функцией, без того, что движок забивает процессор и замораживает приложение, как маньяк. Это 2015 год, и вы не сможете разбить весь веб-браузер с while(1). У нас есть Flash для таких вещей.
Beejor

661

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

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

редактировать

Печально известный сон или задержка функционирования на любом языке широко обсуждается. Некоторые скажут, что всегда должен быть сигнал или обратный вызов для запуска определенной функциональности, другие утверждают, что иногда полезен произвольный момент задержки. Я говорю, что каждому свое и одно правило никогда ничего не может диктовать в этой отрасли.

Написание функции сна просто и стало еще удобнее с обещаниями JavaScript:

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

// Usage!
sleep(500).then(() => {
    // Do something after the sleep!
});

190
В порядке закрытия. function foobar(el) { setTimeout(function() { foobar_cont(el); }, 5000); }
хаос

68
хорошо, а что если код не предназначен для использования на веб-странице?
Эухенио Миро

10
@ EugenioMiró, если код не предназначен для использования на веб-странице, пусть объектная модель хоста реализует метод ожидания. - Я думаю, что вопрос направлен на DOM, который подвержен JavaScript, работающему на веб-страницах.
BrainSlugs83

31
@Nosredna да, мы понимаем, как делать асинхронные вызовы, это не помогает нам спать (). Я хочу, чтобы мои звонки выполнялись в определенном порядке, а данные возвращались в определенном порядке. Я на 5 уровней в глубине цикла. Я хочу заблокировать исполнение. Истинный метод сна не будет «замедлять работу браузера», управление спящими руками обратно к браузеру и любым другим потокам, которым требуется процессорное время, пока оно все еще блокируется.
BrainSlugs83

382
это не ответ на вопрос.
TMS

303

Только для отладки / разработки , я выкладываю это, если это кому-то полезно

Интересные вещи, в Firebug (и, вероятно, других консолях js), ничего не происходит после нажатия enter, только после указанной продолжительности сна (...)

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

Пример использования:

function sleepThenAct(){ sleepFor(2000); console.log("hello js sleep !"); }

36
Это не ответ. Это точно так же, как код в вопросе, за исключением немного короче.
Джеб

16
Ожидание занято, правда? В JS? На секунды? Если я поймаю сайт, делающий это, он будет заблокирован.
Мафу

35
@mafu Вот почему он говорит only for debug/dev... rolleyes
xDaizu

12
НИКОГДА НЕ ДЕЛАЙТЕ ЭТОГО. Это заставит процессор ударить 100% по ядру, которое он выполняет, и заблокирует его.
Ноябрь

3
Это полезно и, возможно, является ЕДИНСТВЕННЫМ способом для сна в приложении javascript из командной строки, потому что async / await не помогает.
Wheezil

177

Я согласен с другими постерами, плохой сон - это просто плохая идея.

Однако setTimeout не задерживает выполнение, он выполняет следующую строку функции сразу после истечения времени ожидания SET, а не после истечения времени ожидания, так что не выполняется та же задача, что и спящий.

Способ сделать это состоит в том, чтобы разбить вашу функцию на части до и после.

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

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

Убедитесь, что имена ваших функций по-прежнему точно описывают, что делает каждый кусок (IE GatherInputThenWait и CheckInput, а не funcPart1 и funcPart2)

редактировать

Этот метод позволяет не выполнять выбранные вами строки кода до ПОСЛЕ вашего тайм-аута, в то же время возвращая управление клиентскому ПК, чтобы выполнить все, что еще было поставлено в очередь.

Далее Править

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


12
Да. Это становится сложным, когда у вас есть цикл или даже вложенный цикл. Вы должны отказаться от своих циклов for и иметь вместо них счетчики.
Носредна

Туш. Я имею в виду, это все еще возможно, но в этом случае уродливо и хакерски. Вы также можете использовать некоторые статические переменные логического состояния, но это тоже довольно хакерски.
DevinB

2
-1 за это. Опять же, это не отвечает на вопрос. Это больше ответ на вопрос типа «Как выполнить функцию асинхронно», который очень сильно отличается от «Как заблокировать выполнение кода».
Дипак ГМ

6
@Nosredna Нет, вы бы использовали закрытие. Например: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }and for(var X = 0; X < 3;X++) { foo(X); }- передается значение X foo, которое затем повторно используется под именем, indexкогда foo_continueв конце концов вызывается.
Изката

2
@ Александр Конечно, так и есть, потому что цель setTimeout () - предотвратить блокировку браузера, выполняя код асинхронно. Поместите console.log()внутреннюю часть foo_continue()в версию setTimeout, и вы получите тот же результат.
Изката

132

Ради любви к $ DEITY, пожалуйста, не делайте функцию сна с занятым ожиданием. setTimeoutи setIntervalделай все что нужно.

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

Каждые две секунды интервал скрывает текст на одну секунду. Здесь показано, как использовать setInterval и setTimeout для отображения и скрытия текста каждую секунду.


3
Ну, не совсем все: setInterval производит намного лучшее впечатление от опроса.
Annakata

3
Что бы этот кусок кода не сдерживал в движке JavaScript?
Дениз Доган

10
Если вам не нужен сон, чтобы быть синхронным, то в этом случае это совершенно правильный вопрос.
Аарон Дюфур

36
Я думаю, что многие из нас могут забыть, что JavaScript не является языком только для браузера. Этот чувак может создавать утилиту командной строки Node, которая требует короткой паузы без необходимости решения всех проблем с областью видимости переменных, которые идут с setTimeout.
Фил ЛаНаса

3
@PhilLaNasa: Если синтаксическое закрытие все еще пугает, нужно серьезно согнуться и проработать Узел 101.
хаос

113

Я знаю, что это немного старый вопрос, но если (как и я) вы используете Javascript с Rhino, вы можете использовать ...

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.
   */
}

4
Это вызов Java?
Кен Шарп

14
Это Java, а не Javascript
РуссоАлександр

18
@RousseauAlexandre Неверно. Это JavaScript, использующий Rhino (в то время это мог быть и Nashorn в наши дни)
mjaggard

71

Если вы используете jQuery, кто-то на самом деле создал плагин «delay», который является не более чем оболочкой для 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;
};

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

$('#warning')
.addClass('highlight')
.delay(1000)
.removeClass('highlight');

4
Это не плохое решение. Сохраняет контекст и цепочность.
Носредна

39
Начиная с jQuery 1.4, .delay()является частью jQuery (хотя семантика отличается от приведенной выше реализации). api.jquery.com/delay
Мэтт Болл

7
Чего не хватало этому вопросу, так это ответа jQuery . Так рада, что мы получили это!
xDaizu

1
Если вам нужна задержка между двумя независимыми вызовами, да. Если вам нужны задержки для замедления цикла, нет.
WGroleau

46

Я также искал решение для сна (не для производственного кода, только для dev / tests) и нашел эту статью:

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

... и вот еще одна ссылка с решениями на стороне клиента: http://www.devcheater.com/

Кроме того, когда вы звоните alert(), ваш код будет также приостановлен, пока отображается предупреждение - нужно найти способ не отображать предупреждение, но получить тот же эффект. :)


35
Я согласен, многие люди говорят: «Нет, не делайте этого в рабочем коде!» Да, я не хочу. Я хочу сделать это в одноразовом тестовом коде, и в результате я не хочу тратить много времени на создание элегантного решения.
user435779

31

Вот простое решение с использованием синхронного XMLHttpRequest:

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

содержимое sleep.php:

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

Теперь назовите это с помощью: sleep (5);


5
@lukad, используйте, setTimeout()если это работает, но если это означает, что нужно распутать 1000 строк обратных вызовов, это может начать выглядеть не шуткой.
pguardiario

11
Уникальный подход, хотя, к сожалению, не асинхронные XMLHttpRequests устарели и будут удалены в будущем. Что забавно, потому что именно этот факт и привел меня к этому вопросу.
15:30

Это на самом деле довольно хорошая идея IMO. Хотя я не думаю, что спящий API (Request URL) должен быть общедоступным, поскольку им можно злоупотреблять.
Вахид Амири

@Beejor думать всегда только о будущем означает жить на футуристической нереальности :-)
user1742529

хорошо, но знаете ли вы, если когда-нибудь интернет работает медленно или время пинга на сайте велико, чем сценарий ожидания будет дольше, чем время спора. Например, если вы используете sleep(300)веб-сайт и ответ занимает 150 мс, тогда код javascript будет находиться в спящем режиме в течение 450 мс. и если интернет-соединение теряется браузером, оно будет работать только 0 мс. Так что это не лучшее решение
Чаухан

30

Ну вот. Как говорится в коде, не будьте плохим разработчиком и используйте это на веб-сайтах. Это функция полезности разработки.

// 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) {}
}

17
Это в основном то же самое, что и ОП.
Эндрю Барбер

5
Чтобы быть более точным, это то, что ОП попросил АЛЬТЕРНАТИВУ.
WGroleau

Решение не очень хорошее, но в некоторых местах async/awaitоно, к сожалению, не отвечает, и мы вынуждены использовать его обязательно.
Наби КАЗ

21

Мне лично нравится простое

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

тогда:

sleep(2); // Sleeps for 2 seconds

Я использую его все время для создания фальшивого времени загрузки при создании скриптов в P5js


3
Я рассматриваю это как наиболее оптимизированную версию основного вопроса: он не выполняет никаких математических операций внутри цикла, а представляет собой простое сравнение. Это немного трудно читать, хотя.
хегез

4
НИКОГДА НЕ ДЕЛАЙТЕ ЭТОГО. Вы проверили использование процессора, пока эта функция работает? Это должно быть близко к 100%, если вы даете на это достаточно времени.
Ноябрь

2
@hegez: Учитывая, что цикл будет работать в течение фиксированного количества часов на настенных часах, несмотря ни на что, похоже, что оптимизация цикла отчасти не относится к делу.
ShadowRanger

@noego Как так? Я только что протестировал в Node 10, у меня вообще нет изменения
загрузки

@melMass Эта функция просто блокирует поток узлов на n секунд, поддерживая процессор на 100%. Это «решение» является крайне плохой идеей по этим двум причинам (блокировка + убийца процессора). Ожидание должно быть неблокирующим, поэтому асинхронным.
Джереми Тилле

20

Первый:

Определите функцию, которую вы хотите выполнить следующим образом:

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

Затем запланируйте его выполнение с помощью метода setTimeout:

setTimeout(alertWorld,1000)

Обратите внимание на две вещи

  • второй аргумент - время в миллисекундах
  • в качестве первого аргумента вы должны передать только имя (ссылку) функции без скобок


18

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

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

Это, вероятно, ближе всего к тому, что просто делает то, что вы хотите.

Обратите внимание: если вам нужно несколько снов, это может привести к неприятным последствиям, и вам, возможно, придется пересмотреть свой дизайн.


это тот, который работал для меня на настольных браузерах и старом мобильном телефоне. Другие, которые я пробовал, не работали на всех.
Майк

10

Для браузеров, я согласен, что setTimeout и setInterval - путь.

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

Если вы используете node.js и meteor, возможно, вы столкнулись с ограничениями использования setTimeout в волокне. Вот код для сна на стороне сервера.

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

Смотрите: https://github.com/laverdet/node-fibers#sleep


Server may require a blocking function... Я не понимаю, как принудительно блокировать единственный поток в Node и заставить весь сервер не отвечать на запросы в течение нескольких секунд - хорошая идея, но что угодно
Джереми Тилле

10

Я бы инкапсулировал setTimeOut в Promise для согласованности кода с другими асинхронными задачами: Демонстрация в Fiddle

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

Используется так:

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

Синтаксис легко запомнить, если вы использовали Обещания.


4
Почему это лучше, чем просто использовать setTimeout (function () {/ * сделать что-то * /}, 2000) ;?
JSideris

10

Обновление 2019 с использованием Atomics.wait

Должен работать в узле 9.3 или выше.

Мне нужен был довольно точный таймер в Node.js, и он прекрасно работает для этого. Однако кажется, что поддержка браузеров крайне ограничена.

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

Пробежал несколько 10 секундных таймеров.

С setTimeout я получаю ошибку до 7000 микросекунд. (7мс)

С Atomics моя ошибка кажется меньше 600 микросекунд. (0.6ms)

Обновление 2020: вкратце

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

из которых страница на стороне сервера, например sleep.jsp, выглядит

<%
try{
  Thread.sleep(Long.parseLong(request.getParameter("millis")));
}catch(InterruptedException e){}
%>

На мой взгляд, лучше, чем принятое решение, которое не может быть реализовано как простая функция без async / await в вызывающей стороне.
GroovyDotCom

да, до тех пор, пока вы знаете, что это блокирует, а это обычно не очень хорошо
Kapytanhook

Довольно круто, но тот факт, что это действительно поддерживается только в Chrome и Firefox , не делает его очень пригодным для использования в Интернете. (Ноябрь 2019)
JGreatorex

9

Большинство ответов здесь ошибочны или, по крайней мере, устарели. Нет причин, по которым javascript должен быть однопоточным, и на самом деле это не так. Сегодня все основные браузеры поддерживают работников, до этого другие среды исполнения javascript, такие как Rhino и Node.js, поддерживали многопоточность.

«Javascript является однопоточным» не является правильным ответом. Например, выполнение функции сна на рабочем месте не будет блокировать любой код, выполняемый в потоке пользовательского интерфейса.

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

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

Эта имитация сна отличается от истинной функции сна, поскольку она не блокирует поток. Это просто сахар поверх текущей функции javascript setTimeout. Этот тип функциональности был реализован в Task.js и должен работать сегодня в Firefox.


Рабочие не реализованы в IE, по крайней мере, до версии 10. Который в настоящее время представляет большое количество пользователей.
Beejor

Правда, и даже тогда это не практично для реализации sleepс использованием нескольких работников. При использовании Node.js функции генератора уже реализованы и могут использоваться как описано. Основные браузеры не все реализованные генераторы на сегодняшний день.
Габриэль Ратенер

8

Я искал / гуглил довольно много веб-страниц на javascript sleep / wait ... и НЕТ ответа, если вы хотите, чтобы javascript был "RUN, DELAY, RUN" ... то, что большинство людей получило, было либо "RUN, RUN (бесполезно) прочее), «БЕГ» или «БЕГ, БЕГ + отложенный БЕГ» ....

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

// ......................................... // пример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>

// .................................... // пример2:

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

// ................. пример3:

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

5
Хорошо, это работает с setTimeput, но трудно увидеть, что происходит. Использование самого setTimeout проще, чем это.
naugtur

7
function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

Это так же, как реальный вопрос. Не имеет особого смысла делать это реальным ответом.
EML

2
Не очень хорошее решение - с помощью этого в Selenium JavaScriptExecutor примерно 50% времени зависает мой браузер Chrome на 2104 MacBook Pro.
Эмери

7

Самое короткое решение без каких-либо зависимостей:

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

Это не работает в IE11. Мы получаем синтаксическую ошибку для функции стрелки.
DDphp

@ Использование Java-DKawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a

6

Вы не можете так спать в JavaScript, или, скорее, не должны. Запуск цикла sleep или while приведет к зависанию браузера пользователя до завершения цикла.

Используйте таймер, как указано в ссылке, на которую вы ссылались.


6

Один из сценариев, в котором вам может потребоваться функция sleep () вместо использования setTimeout (), - это если у вас есть функция, реагирующая на щелчок пользователя, который в конечном итоге приведет к открытию нового, т.е. всплывающего окна, и вы инициировали некоторую обработку, которая требует короткого периода завершить до отображения всплывающего окна. Перемещение открытого окна в закрытие означает, что оно обычно блокируется браузером.


6

Я могу понять назначение функции сна, если вам приходится иметь дело с синхронным выполнением. Функции setInterval и setTimeout создают поток параллельного выполнения, который возвращает последовательность выполнения обратно в основную программу, что неэффективно, если вам приходится ждать заданного результата. Конечно, можно использовать события и обработчики, но в некоторых случаях это не то, что предназначено.


6

Добавляю мои два бита. Я нуждался в занятом ожидании для целей тестирования. Я не хотел разбивать код, так как это было бы много работы, поэтому простой for сделал это для меня.

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

Я не вижу никаких недостатков в этом, и это помогло мне.


Это может быть скомпилировано.
Виктор Сер

Пожалуйста, не делай так. Это блокирующий вызов сна, что означает, что никакой другой javascript не может быть запущен, пока ваш код перегружает поток JS.
Стив Мидгли

5
@SteveMidgley «никакой другой javascript [не может работать], пока ваш код перегружает поток JS», мне кажется, это именно то, что ОП хочет сделать ¯_ (ツ) _ / ¯
drigoangelo

1
Я только что провел несколько тестов, и кажется, что даже пустой цикл заблокирует браузер и процессор (не только JavaScript). И использование forциклов почти всегда выполняется немедленно, независимо от максимального значения для i, и даже со сложным математическим кодом, размещенным внутри. Так что, если вы не ждете всего несколько миллисекунд, кажется, что в JS все равно не будет возможности изящно поспать.
Бежор

1 миллион слишком большой. Для меня достаточно 10к
Влад

6

Это можно сделать с помощью метода сна Java. Я протестировал его в FF и IE, и он не блокирует компьютер, не проверяет ресурсы и не вызывает бесконечные попадания на сервер. Похоже, чистое решение для меня.

Сначала вы должны загрузить Java на страницу и сделать ее методы доступными. Для этого я сделал это:

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

Затем все, что вам нужно сделать, когда вы хотите безболезненную паузу в вашем JS, это:

java.lang.Thread.sleep(xxx)

Где ххх - время в миллисекундах. В моем случае (для обоснования) это было частью выполнения внутреннего заказа в очень маленькой компании, и мне нужно было распечатать счет, который должен был быть загружен с сервера. Я сделал это, загрузив счет (как веб-страницу) в iFrame, а затем распечатал iFrame. Конечно, мне пришлось ждать полной загрузки страницы, прежде чем я смог напечатать, поэтому JS пришлось сделать паузу. Я достиг этого, заставив страницу счета (в iFrame) изменить скрытое поле формы на родительской странице с помощью события onLoad. И код на родительской странице для печати счета-фактуры выглядел следующим образом (несущественные части вырезаны для ясности):

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

Таким образом, пользователь нажимает кнопку, скрипт загружает страницу счета-фактуры, затем ждет, проверяя каждую четверть секунды, чтобы увидеть, завершена ли загрузка страницы счета-фактуры, а затем выскакивает диалоговое окно печати, чтобы пользователь мог отправить ее на принтер. QED.


12
Кажется, это чудовищное решение, если учесть, чего хотел достичь автор.
xaralis

2
Это зависит от Java-апплетов, которые устарели.
Вахид Амири

6

Многие ответы не (прямо) отвечают на вопрос, и не этот ...

Вот мои два цента (или функции):

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

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

Версии CoffeeScript:

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

Затем вы можете красиво использовать их с анонимными функциями:

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

Теперь он легко читается как "после N миллисекунд, ..." (или "каждые N миллисекунд, ...")


5

Для конкретного случая, когда требуется разметить набор вызовов, выполняемых циклом, вы можете использовать что-то вроде приведенного ниже кода с прототипом. Без прототипа вы можете заменить функцию задержки на 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)
}

5

Если вы находитесь на node.js, вы можете взглянуть на волокна - собственное расширение C для узла, своего рода многопоточное моделирование.

Это позволяет вам сделать реальный sleepспособ, который блокирует выполнение в волокне, но не блокирует основной поток и другие волокна.

Вот пример, только что из собственного readme:

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

- и результаты:

$ 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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.