Що таке JavaScript-версія ()?


2335

Чи є кращий спосіб інженерії sleepв JavaScript, ніж наступна pausecompфункція ( взята звідси )?

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

Це не дублікат режиму сну в JavaScript - затримка між діями ; Я хочу справжнього сну в середині функції, а не затримки перед тим, як виконати фрагмент коду.


4
Це слід встановити в середині часу, якщо я використовую setTimeout, а час продовжуватиме обробляти і виводити в чергу більше setTimeouts, які в кінцевому підсумку працюватимуть одночасно і створюватимуть трохи співвідношення між собою
fmsf

159
Це жахливе рішення - ви збираєтеся жувати цикли обробки, не роблячи нічого.
17 від 26

12
Єдина мета сну - опитування або очікування зворотного дзвінка - setInterval і setTimeout роблять і те, і інше краще, ніж це.
annakata

1
Можливо, ви можете робити все, що завгодно, продовжуючи стиль проходження в JavaScript. Погляньте на цю статтю.
Огнян Димитров

Відповіді:


2559

Оновлення 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
Яка поточна підтримка браузера для цього? Я б не вважав попередні рішення "застарілими", поки це рішення не буде підтримано переважною більшістю браузерів або, принаймні, всіма загальними. Навпаки, я вважав би це рішення цікавим, але непридатним / непрактичним, поки він не отримав широкої підтримки.
Елвін Томпсон

74
Це не "справжній сон" і не дає відповіді на питання. Людина, яка запитала, чітко розрізняла 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, але не з точністю в режимі реального часу. Зрештою, це система на основі подій. Якщо виклики асинхронізації завершено, подія запускається. Я не бачу жодної причини, чому те ж саме неможливо зробити, коли видається сон (), після якого керування повертається до браузера, поки сплячий не закінчиться, повертаючи контроль до функції виклику. І так, я також погоджуюся, що іноді спати зручно, особливо коли розробники ПЕРЕД ви накрутили дизайн настільки сильно, що у вас немає іншого виходу, окрім повністю рефакторингу, на який у вас немає часу
Лоуренс

Спробуйте Hypnotic, що випливає цю ідею: coolwanglu.github.io/hypnotic/web/demo.html
Тескатліпокі

4
Виклик однопотокового JavaScript - це лише міф. Хоча це може бути технічно правильним, але він функціонує як багатопотоковий мов. Моделювати вилку () тривіально просто, і хоча результат () насправді не реалізований, ви можете наблизитися, використовуючи спільну пам'ять для блокування / семафору. Для пересічного програміста є сенс трактувати це як багатопотокове; технічна назва має значення лише для розробників мови.
Benubird

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

660

У 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 рівнів глибоко в циклі for. Я хочу блокувати виконання. Справжній спосіб сну не буде "уповільнювати браузер", режими сну повертаються до браузера та будь-яких інших потоків, які хочуть часу процесора, поки він все ще блокується.
BrainSlugs83

382
це не відповідь на запитання.
TMS

303

Лише для налагодження / dev , я публікую це, якщо комусь це корисно

Цікаві речі, в 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? На секунди? Якщо я зафіксую веб-сайт, що робить це, він буде заблокований.
мафу

34
@mafu Ось чому написано only for debug/dev... rolleyes
xDaizu

11
НІКОЛИ НЕ РОБИТИ ЦЕ. Це зробить процесор на 100% ударом по основній ядрі, яку він виконує, і заблокує його.
noego

3
Це корисно, і, можливо, ТІЛЬКИ спосіб сну в межах програмного забезпечення javascript для командного рядка, оскільки async / wait не корисний.
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
Так. Де це стає складним, коли у вас є петля або рівний вкладений цикл. Ви повинні відмовитися від циклів і замість цього мати лічильники.
Носредна

Touché. Я маю на увазі, все одно це було б можливо, але в цьому випадку потворне і хакерське. Ви також можете використовувати деякі статичні змінні булевого стану, але це також досить хакі.
DevinB

2
-1 для цього. Знову ж таки, це не дає відповіді на питання. Це більше відповідь на питання типу "Як виконати функцію асинхронно", що сильно відрізняється від "Як заблокувати виконання коду".
Діпак ГМ

6
@Nosredna Ні, ви б використовували закриття. Наприклад: function foo(index) { setTimeout(function() { foo_continue(index); }, 10000); }і 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.
Phil LaNasa

3
@PhilLaNasa: Якщо синтаксичне закриття все-таки лякає, потрібно серйозно скрутитися і працювати над Node 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
RousseauAlexandre

18
@RousseauAlexandre Неправильно. Це JavaScript, що використовує Rhino (на той час це може бути однаково Nashorn в ці дні)
mjaggard

71

Якщо ви використовуєте jQuery, хтось фактично створив плагін "затримка", це не що інше, як обгортка для 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

Я також шукав рішення для сну (не для виробничого коду, лише для розробників / тестів) і знайшов цю статтю:

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

Тепер назвіть це за допомогою: сон (5);


5
@lukad, Використовуйте, setTimeout()якщо це працює, але якщо це означає розгадування 1000 рядків зворотних викликів, це може почати не схоже на жарт.
pguardiario

11
Унікальний підхід, хоча, на жаль, неасинхронний XMLHttpRequests застарілий і буде видалений у майбутньому. Що смішно, адже саме цей факт спонукав мене до цього питання.
Bejjor

Це насправді досить гарна ідея ІМО. Хоча я не думаю, що API сну (URL-адреса запиту) повинен бути відкритим, оскільки ним можна зловживати.
Вахід Амірі

@ Beejor завжди думає лише про майбутнє, означає жити на футуристичній нереальності :-)
user1742529

приємно, але чи знаєте ви, що коли-небудь Інтернет повільний або веб-сайт пінг часу більше, ніж це буде спати сценарій більше, ніж аргумент часу. Наприклад, якщо ви використовуєте sleep(300)і веб-сайт потребує часу 150 мс для відповіді, ніж код JavaScript буде сном протягом 450 мс. і якщо браузер втратить з’єднання з Інтернетом, він буде працювати лише 0 мс. Тож це не краще рішення
H Chauhan

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
Я вважаю це найбільш оптимізованою версією головного питання: він не робить жодної математики всередині циклу, а просто порівняння. Трохи важко читати тхо.
hegez

4
НІКОЛИ НЕ РОБИТИ ЦЕ. Ви перевіряли використання процесора під час роботи цієї функції? Це повинно бути близько 100%, якщо ви приділите для цього достатньо часу.
noego

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

@noego Як це? Я щойно тестував у вузлі 10, у мене взагалі не змінюється використання процесора
melMass

@melMass Ця функція просто блокує потік Node протягом n секунд, зберігаючи процесор на 100% зайнятим. Це "рішення" є вкрай поганою ідеєю з цих двох причин (блокування + вбивця процесора). Очікування, що HAS буде не блокуючим, тому є асинхронним.
Джеремі Тілль

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 та метеор, можливо, ви зіткнулися з обмеженнями використання 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 у обіцянку за узгодженість коду з іншими асинхронними завданнями: Демо в Fiddle

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

Використовується так:

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

Легко запам’ятати синтаксис, якщо ви використовували Promises.


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,6 мс)

Оновлення 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){}
%>

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

так, поки ви знаєте, що це блокує, і це, як правило, не дуже добре
Kapytanhook

Дуже круто, але той факт, що це дійсно підтримується лише в Chrome і Firefox , не робить його дуже життєздатним для використання в Інтернеті. (Листопад 2019 р.)
JGreatorex

9

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

"Javascript - єдиний потік" - не вірна відповідь. Наприклад, запуск функції сну в межах робочого не блокує жоден код, що працює в потоці ui.

У новіші періоди виконання, що підтримують генератори та вихід, можна створити аналогічні функції функції сну в єдиному потоковому середовищі:

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

Ця імітація сну відрізняється від справжньої функції сну, оскільки не блокує нитку. Це просто цукор поверх поточної функції setTimeout в JavaScript. Цей тип функціоналу реалізований у Task.js і має працювати сьогодні у Firefox.


Працівники не реалізуються в IE, принаймні через версію 10. Що наразі представляє велику кількість користувачів.
Bejjor

Щоправда, і навіть тоді це не практично реалізувати, sleepвикористовуючи декількох працівників. Якщо використання генератора Node.js вже реалізовано, їх можна використовувати, як описано. Основні браузери на сьогодні не всі реалізовані генератори.
Габріель Стайтенер

8

Я шукав / googled досить багато веб-сторінок у режимі сну / очікування javascript ... і немає відповіді, якщо ви хочете, щоб javascript "RUN, DELAY, RUN" ... те, що отримала більшість людей, було або "RUN, RUN (марно речі), RUN "або" RUN, RUN + затримка RUN "....

Тож я з’їв трохи гамбургерів і задумався ::: ось рішення, яке працює ... але ви повинні порубати свої запущені коди ... ::: так, я знаю, це просто прочитання рефакторингу .. ... все ще ...

// ......................................... // example1:

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

// ................. приклад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
Не вдале рішення - використовуючи це в JavaScriptExecutor Selenium, вішає мій браузер Chrome близько 50% часу на 2104 MacBook Pro.
наждак

7

Найкоротше рішення без будь-яких залежностей:

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

Він не працює в IE11. Ми отримуємо синтаксичну помилку для функції стрілки.
DDphp

@ Java-DK useawait new Promise(function(resolve) { setTimeout(resolve, 5000); });
k06a

6

Ви не можете спати так, як у JavaScript, а точніше - не слід. Виконання циклу сну або деякого часу призведе до того, що браузер користувача зависне, доки цикл не буде виконаний.

Використовуйте таймер, як зазначено у посиланні, на яке ви посилалися.


6

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


6

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


6

Додавання моїх двох біт. Мені потрібно було зайнято-чекати для тестування. Я не хотів розділяти код, тому що це буде багато роботи, тому простий для мене це зробив.

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

Я не бачу жодних недоліків у цьому, і це зробило для мене трюк.


Це може бути складено далеко.
Віктор Шер

Будь ласка, не робіть цього так. Це блокуючий дзвінок сну, який означає, що жоден інший JavaScript не може працювати, поки ваш код зачепить потік JS.
Стів Мідглі

5
@SteveMidgley "жоден інший javascript [не в змозі] запустити, поки ваш код зачіпає потік JS", мені здається, саме те, що хоче зробити ОП ¯_ (ツ) _ / ¯
drigoangelo

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

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

Дуже багато відповідей (безпосередньо) не відповідають на питання, і жодна з них не відповідає ...

Ось два мої центи (або функції):

Якщо ви хочете менше незграбних функцій, ніж setTimeoutі 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таким чином, що блокує виконання у волокні, але це не блокування в основній нитці та інших волокнах.

Ось приклад із їхнього власного читання:

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