Сон в JavaScript - задержка между действиями


129

Есть ли способ заснуть в JavaScript, прежде чем он выполнит другое действие?

Пример:

 var a = 1+3;
 // Sleep 3 seconds before the next action here
 var b = a + 4;

Ответы:


140

Вы можете использовать setTimeoutдля достижения аналогичного эффекта:

var a = 1 + 3;
var b;
setTimeout(function() {
    b = a + 4;
}, (3 * 1000));

На самом деле это не «спящий» JavaScript - он просто выполняет переданную функцию по setTimeoutистечении определенного времени (указанного в миллисекундах). Хотя можно написать функцию сна для JavaScript, по возможности лучше использовать, setTimeoutпоскольку она не замораживает все в течение периода сна.


9
Также посмотрите setInterval (). Это похоже на setTimeout (), но ваша функция вызывается несколько раз (пока вы ее не остановите), что полезно, если вы хотите что-то сделать во время сна (например, обновлять прогресс, сохранять какое-то внутреннее состояние или что-то еще).
Андерс Сандвиг

5
Это не отвечает на вопрос. Вопрос требует эквивалента "сна", но это не так.
felwithe

Хотя этот ответ не соответствует заданному вопросу, но он более полезен, чем цикл и сравнение Date.now (). Никто, что использовать заблокированный шлейф спящий режим.
Ли

2
Если, конечно, блокирующий цикл - это именно то , что кому-то нужно.
Вонко Разумный

55

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

function pauseBrowser(millis) {
    var date = Date.now();
    var curDate = null;
    do {
        curDate = Date.now();
    } while (curDate-date < millis);
}

Не используйте new Date()в цикле, если вы не хотите тратить впустую память, вычислительную мощность, батарею и, возможно, весь срок службы вашего устройства.


8
Этот ответ заслуживает большего количества голосов. Помещение вопроса в звездочку только причина этого ответа.
jagc 06

как насчет предупреждения "слишком много рекурсии"?
Оки Эри Ринальди

1
@OkiErieRinaldi Там нет рекурсии, это всего лишь цикл.
Родриго

7
@ 3.1415926535897932384626433833 Ну кто-то просил функцию "сна", вот что тут. Один раз использовал, точно не помню, для какой отладки. Если он мне когда-нибудь понадобится, я точно знаю, где его найти. Если вы предпочитаете другую функцию, это ваш выбор. Разве не здорово иметь возможность выбирать?
Родриго

2
«Ожидание занято».
Zeek2 07

13

Версия ECMAScript 6, использующая генераторы с yield для «блокировки кода»:

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

let sleeptime = 100
function* clock()
{
    let i = 0
    while( i <= 10000 )
    {
        i++
        console.log(i); // actually, just do stuff you wanna do.
        setTimeout(
            ()=>
            {
                clk.next()
            }
            , sleeptime
        )
        yield
    }
}

let clk = clock()
clk.next()

функция *

() => стрелочная функция

Вы также можете связать события через обещания :

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


sleep(1000).then(function()
{
    console.log('1')
    sleep(1000).then(function()
    {
        console.log('2')
    })
})

Или гораздо более простой и менее изящный способ был бы

function sleep(ms, f)
{
    return(
        setTimeout(f, ms)
    )
}


sleep(500, function()
{
    console.log('1')
    sleep(500, function()
    {
        console.log('2')
    })
})
console.log('Event chain launched')

Если вы просто ждете, когда произойдет какое-то условие, вы можете подождать вот так

function waitTill(condition, thenDo)
{
    if (eval(condition))
    {
        thenDo()
        return
    }

    setTimeout(
        ()    =>
        {
            waitTill(condition, thenDo)
        }
        ,
        1
    )
}

x=0

waitTill(
    'x>2 || x==1'
    ,
    ()    =>
    {
        console.log("Conditions met!")
    }
)

// Simulating the change
setTimeout(
    () =>
    {
        x = 1
    }
    ,
    1000
)


11

Обновление 2018

Последние версии Safari, Firefox и Node.js теперь также поддерживают async / await / promises.

Использование async / await / Promises:

(С 1/2017 поддерживается в Chrome, но не в Safari, Internet Explorer, Firefox, Node.js)

'use strict';

function sleep(ms) {
  return new Promise(res => setTimeout(res, ms));
}

let myAsyncFunc = async function() {
  console.log('Sleeping');
  await sleep(3000);
  console.log('Done');
}

myAsyncFunc();

Обновление 2017 г.

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

Используя функцию генератора:

'use strict';

let myAsync = (g) => (...args) => {
    let f, res = () => f.next(),
        sleep = (ms) => setTimeout(res, ms);
    f = g.apply({sleep}, args); f.next();
};

let myAsyncFunc = myAsync(function*() {
    let {sleep} = this;
    console.log("Sleeping");
    yield sleep(3000);
    console.log("Done");
});

myAsyncFunc();

Обратите внимание на то, что оба эти решения носят асинхронный характер. Это означает, что myAsyncFunc (в обоих случаях) вернется во время сна.

Важно отметить, что этот вопрос отличается от того, что такое JavaScript-версия sleep ()? где инициатор запроса запрашивает настоящий сон (отсутствие выполнения другого кода в процессе), а не задержку между действиями.


1
Лучший ответ на данный момент !! Я потратил 30 минут на поиски везде, чтобы найти это .. большое спасибо !!!
538ROMEO

1
Я пропустил этот ответ, пока искал решение, и заново изобрел велосипед: D Если бы я только увижу его, прежде чем он сэкономит мне часы !! Upvoted!
sserzant

let co = gen => (...args) => { let iter = gen(...args); let resume = () => new Promise((resolve, reject) => { let result = iter.next(); if (result.done) resolve(result.value); else Promise.resolve(result.value).then(resume).then(resolve, reject); }); return resume(); };позволит вам let asyncAdd = co(function* (a, b) { console.log('Sleeping'); yield sleep(3000); console.log('Done'); return a + b; }); asyncAdd(3, 4).then(console.log);использовать определение sleep()из вашего второго блока кода.
Патрик Робертс,

3

Если вам нужны менее неуклюжие функции, чем 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 миллисекунд, ...»)


2

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

async yourAsynchronousFunction () {

    var a = 1+3;

    await new Promise( (resolve) => {
        setTimeout( () => { resolve(); }, 3000);
    }

    var b = a + 4;

}

2

Вот очень простой способ сделать это, который «ощущается» как синхронный сон / пауза, но является допустимым асинхронным кодом js.

// Create a simple pause function
const pause = (timeoutMsec) => new Promise(resolve => setTimeout(resolve,timeoutMsec))

async function main () {
    console.log('starting');
    // Call with await to pause.  Note that the main function is declared asyc
    await pause(3*1000)
    console.log('done');
}


1

Вы можете использовать простой javascript, это вызовет вашу функцию / метод через 5 секунд:

setTimeout(()=> { your_function(); }, 5000);

0

Есть несколько способов решить эту проблему. Если мы используем setTimeoutфункцию, давайте сначала познакомимся с ней. Эта функция имеет три параметра: functionили code, delay(в миллисекундах) и parameters. Поскольку параметр функции или кода является обязательным, остальные необязательны. Если вы не вошли в задержку , она будет установлена ​​на ноль.

Для получения более подробной информации setTimeout() перейдите по этой ссылке .

Упрощенная версия:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(function(){ 
    b = a + 4; 
    console.log('b = ' + b);
}, 1000);

output:
a = 4
24 -> Номер-идентификатор списка активных таймаутов
b = 8


Используя передачу параметров:

var a = 1 + 3;
var b;
console.log('a = ' + a);
setTimeout(myFunction, 1000, a);

function myFunction(a)
{
    var b = a + 4;
    console.log('b = ' + b);
}

вывод:
a = 4
25 -> Номер-идентификатор списка активных таймаутов
b = 8



Поддержка браузера:

Chrome Firefox Edge Safari Opera
1,0 1,0 4,0 1,0 4,0

0

Это моя модель, которая показывает, как «засыпать» или «DoEvents» в javascript с помощью функции генератора (ES6). Прокомментированный код:

<html>
<head>
<script>
  "use strict"; // always
  // Based on post by www-0av-Com /programming/3143928
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
  var divelt, time0, globaln = 0; // global variables
  var MainGenObj = Main(); // generator object = generator function()
window.onload = function() {
  divelt = document.getElementsByTagName("body")[0]; // for addline()
  addline("typeof Main: " + typeof Main);
  addline("typeof MainDriver: " + typeof MainDriver);
  addline("typeof MainGenObj: " + typeof MainGenObj);
  time0 = new Date().valueOf(); // starting time ms
  MainDriver(); // do all parts of Main()
}
function* Main() { // this is "Main" -- generator function -- code goes here
  // could be loops, or inline, like this:

  addline("Part A, time: " + time() + ", " + ++globaln); // part A
  yield 2000;                    // yield for 2000 ms (like sleep)

  addline("Part B, time: " + time() + ", " +  ++globaln); // part B
  yield 3000;                    // yield for 3000 ms (or like DoEvents)

  addline("Part Z, time: " + time() + ", " +  ++globaln); // part Z (last part)
  addline("End, time: " + time());
}
function MainDriver() { // this does all parts, with delays
  var obj = MainGenObj.next(); // executes the next (or first) part of Main()
  if (obj.done == false) { // if "yield"ed, this will be false
    setTimeout(MainDriver, obj.value); // repeat after delay
  }
}
function time() { // seconds from time0 to 3 decimal places
  var ret = ((new Date().valueOf() - time0)/1000).toString();
  if (ret.indexOf(".") == -1) ret += ".000";
  while (ret.indexOf(".") >= ret.length-3) ret += "0";
  return ret;
}
function addline(what) { // output
  divelt.innerHTML += "<br />\n" + what;
}
</script>
</head>
<body>
<button onclick="alert('I\'m alive!');"> Hit me to see if I'm alive </button>
</body>
</html>

0

Попробуйте эту функцию:

const delay = (ms, cb) => setTimeout(cb, ms)

Вот как вы его используете:

console.log("Waiting for 5 seconds.")
delay(5000, function() {
  console.log("Finished waiting for 5 seconds.")
})

Или используйте стиль обещания:

const delay = ms => new Promise(resolve => {
    setTimeout(resolve, ms)
})

Вот демо .

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