Сон у 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
Це не відповідає на запитання. Питання задає еквівалент "сну", якого це не так.
Felwit

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

2
Якщо, звичайно, блокуючий цикл - це саме те , що хтось хоче.
Wonko the Sane

55

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

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

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


8
Ця відповідь заслуговує на більше голосів. Зображення з цим питанням просто причина цієї відповіді.
jagc

як щодо попередження "занадто багато рекурсії"?
Окі Ері Рінальді

1
@OkiErieRinaldi Там немає рекурсії, це лише цикл.
Родріго

7
@ 3.1415926535897932384626433833 Ну, хтось попросив функцію "сну", ось що тут. Я використовував це один раз, не можу точно пригадати, для якої налагодження. Якщо мені це буде потрібно ще раз, я точно знаю, де його знайти. Якщо ви віддаєте перевагу іншій функції, це ваш вибір. Хіба це не чудово, що можна вибрати?
Родріго

2
"Зайняте очікування".
Zeek2

13

Версія ECMAScript 6, використовуючи генератори з урожайністю для "блокування коду":

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

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 / очікувати / обіцянки.

Використання асинхронізації / очікування / Обіцянь:

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

Використання функції генератора:

'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-версія ()? де запитувач запитує реального сну (ніякого іншого виконання коду в процесі), а не затримки між діями.


1
Найкраща відповідь поки !! Я витратив 30 хв на пошук скрізь, щоб знайти це .. великий THX !!!
538ROMEO

1
Я пропустив цю відповідь, шукаючи рішення і заново винайшов велосипед: D Якби я бачив його, перш ніж це врятувало б мені години !! Оголошено!
сержант

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

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

вихід:
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.