javascript - пауза - js sleep wait




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

2017 обновление

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

demo();

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

Вы можете попробовать этот код в прямом эфире на Runkit . Обратите внимание, что,

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

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

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

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

npm install babel-cli --save

Создайте .babelrc с помощью:

{
  "plugins": [
    "transform-async-to-generator",
  ]
}

Затем запустите свой код с помощью

node_modules/babel-cli/bin/babel-node.js sleep.js

Но опять же, вам это не нужно, если вы используете Node 7 или более позднюю версию, или если вы ориентируетесь на современные браузеры.

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

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

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


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

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

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

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

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


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

Вот простое решение с использованием синхронного 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);


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


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

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

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


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

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

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

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


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

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

затем:

sleep(2); // Sleeps for 2 seconds

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


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


Первый:

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

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

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

setTimeout(alertWorld,1000)

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

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

Я знаю, что это немного старый вопрос, но если (как я) вы используете 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.
   */
}

Я искал / googled несколько веб-страниц на javascript sleep / wait ... и нет ответа, если вы хотите, чтобы javascript «RUN, DELAY, RUN» ... то, что большинство людей получили, было либо: «RUN, RUN (бесполезно материал), RUN "или" RUN, RUN + delayed 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>

// ................. example3:

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

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

Однако 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)

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

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

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

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


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

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

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

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


Если вы правильно выполняете функцию сна

var sleep = function(period, decision, callback){
    var interval = setInterval(function(){
        if (decision()) {
            interval = clearInterval(interval);
            callback();
        }
    }, period);
}

и у вас есть асинхронная функция для вызова нескольких раз

var xhr = function(url, callback){
    // make ajax request
    // call callback when request fulfills
}

И вы настраиваете свой проект следующим образом:

var ready = false;

function xhr1(){
    xhr(url1, function(){ ready = true;});  
}
function xhr2(){
    xhr(url2, function(){ ready = true; }); 
}
function xhr3(){
    xhr(url3, function(){ ready = true; }); 
}

Тогда вы можете сделать это:

xhr1();
sleep(100, function(){ return done; }, xhr2);
sleep(100, function(){ return done; }, xhr3);
sleep(100, function(){ return done; }, function(){
    // do more
});

Вместо бесконечного отклика обратного вызова:

xhr(url1, function(){
    xhr2(url2, function(){
        xhr3(url3, function(){
            // do more
        });
    });
});

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

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

Если вы хотите меньше clunky функций, чем 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 миллисекунд, ...»)


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

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


Если вы находитесь на узле.js, вы можете взглянуть на fibers - родное расширение 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)

Старый вопрос с 2009 года. Теперь в 2015 году возможно новое решение с генераторами, определенными в ECMAscript 2015, а также ES6. Он был одобрен в июне, но раньше он был реализован в Firefox и Chrome. Теперь функция сна может быть сделана не занятой, неблокирующей и вложенной внутренней петлей и подфункций без замораживания браузера. Нужен только чистый JavaScript, нет библиотек или фреймворков.

В приведенной ниже программе показано, как sleep()и что runSleepyTask()можно сделать. sleep()Функция только yieldзаявление. Это так просто, что на самом деле проще написать yieldзаявление непосредственно вместо вызова sleep(), но тогда не будет слова сна :-). Результат возвращает значение времени next()внутри метода wakeup()и ждет. Фактический «спящий» делается с wakeup()использованием старого добрых setTimeout(). При обратном вызове next()метод запускает yieldутверждение, и «магия» доходности заключается в том, что все локальные переменные и весь стек вызовов вокруг него все еще остаются нетронутыми.

Функции, которые используют sleep () или yield, должны определяться как генераторы. Легко сделать, добавив звездочку к ключевому слову function*. Выполнять генератор немного сложнее. При вызове с ключевым словом newгенератор возвращает объект, который имеет этот next()метод, но тело генератора не выполняется (ключевое слово newявляется необязательным и не имеет значения). next()Метод вызывает выполнение тела генератора , пока он не встречает yield. Функция обертки runSleepyTask()запускает пинг-понг: next()ждет a yieldи yieldждет next().

Другой способ вызвать генератор - с ключевым словом yield*, здесь он работает как простой вызов функции, но также включает в себя способность возвращаться next().

Все это демонстрируется на примере drawTree(). Он рисует дерево с листьями на вращающейся 3D-сцене. Дерево рисуется как ствол с тремя частями вверху в разных направлениях. Затем каждая часть рисуется как другое, но меньшее дерево, вызывая drawTree()рекурсивно после короткого сна. Очень маленькое дерево рисуется только как лист.

Каждый лист имеет свою собственную жизнь в отдельной задаче, начатой ​​с runSleepyTask(). Он рождается, растет, сидит, исчезает, падает и умирает growLeaf(). Скорость контролируется sleep(). Это демонстрирует, как легко выполнять многозадачность.

function* sleep(milliseconds) {yield milliseconds};

function runSleepyTask(task) {
    (function wakeup() {
        var result = task.next();
        if (!result.done) setTimeout(wakeup, result.value);
    })()
}
//////////////// written by Ole Middelboe  /////////////////////////////

pen3D =setup3D();
var taskObject = new drawTree(pen3D.center, 5);
runSleepyTask(taskObject);

function* drawTree(root3D, size) {
    if (size < 2) runSleepyTask(new growLeaf(root3D))
    else {
        pen3D.drawTrunk(root3D, size);
        for (var p of [1, 3, 5]) {
            var part3D = new pen3D.Thing;
            root3D.add(part3D);
            part3D.move(size).turn(p).tilt(1-p/20);
            yield* sleep(50);
            yield* drawTree(part3D, (0.7+p/40)*size);
        }
    }
}

function* growLeaf(stem3D) {
    var leaf3D = pen3D.drawLeaf(stem3D);
    for (var s=0;s++<15;) {yield* sleep(100); leaf3D.scale.multiplyScalar(1.1)}
    yield* sleep( 1000 + 9000*Math.random() );
    for (var c=0;c++<30;) {yield* sleep(200); leaf3D.skin.color.setRGB(c/30, 1-c/40, 0)}
    for (var m=0;m++<90;) {yield* sleep( 50); leaf3D.turn(0.4).tilt(0.3).move(2)}
    leaf3D.visible = false;
}
///////////////////////////////////////////////////////////////////////

function setup3D() {
    var scene, camera, renderer, diretionalLight, pen3D;

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75, 
        window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 15, 20);
    renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    
    directionalLight = new THREE.DirectionalLight(0xffffaa, 0.7);
    directionalLight.position.set(-1, 2, 1);
    scene.add(directionalLight);
    scene.add(new THREE.AmbientLight(0x9999ff));
      
    (function render() {
        requestAnimationFrame(render);
        // renderer.setSize( window.innerWidth, window.innerHeight );
        scene.rotateY(10/60/60);
        renderer.render(scene, camera);
    })();
    
    window.addEventListener(
        'resize',
        function(){
            renderer.setSize( window.innerWidth, window.innerHeight );
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
       }, 
       false
    );
    
    pen3D = {
        drawTrunk: function(root, size) {
            // root.skin = skin(0.5, 0.3, 0.2);
            root.add(new THREE.Mesh(new THREE.CylinderGeometry(size/12, size/10, size, 16), 
                root.skin).translateY(size/2));
            root.add(new THREE.Mesh(new THREE.SphereGeometry(size/12, 16), 
                root.skin).translateY(size));
            return root;
        },
        
        drawLeaf: function(stem) {
            stem.skin.color.setRGB(0, 1, 0);
            stem.add(new THREE.Mesh(new THREE.CylinderGeometry(0, 0.02, 0.6), 
                stem.skin) .rotateX(0.3).translateY(0.3));
            stem.add(new THREE.Mesh(new THREE.CircleGeometry(0.2), 
                stem.skin) .rotateX(0.3).translateY(0.4));
            return stem;
        },
        
        Thing: function() {
            THREE.Object3D.call(this);
            this.skin = new THREE.MeshLambertMaterial({
                color: new THREE.Color(0.5, 0.3, 0.2),
                vertexColors: THREE.FaceColors,
                side: THREE.DoubleSide
            })
        }
    };

    pen3D.Thing.prototype = Object.create(THREE.Object3D.prototype);
    pen3D.Thing.prototype.tilt = pen3D.Thing.prototype.rotateX;
    pen3D.Thing.prototype.turn = pen3D.Thing.prototype.rotateY;
    pen3D.Thing.prototype.move = pen3D.Thing.prototype.translateY;
    
    pen3D.center = new pen3D.Thing;
    scene.add(pen3D.center);
    
    return pen3D;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

3D-материал скрыт внутри setup3D () и включен только, чтобы сделать его менее скучным, чем console.log (). Между прочим, ангелы измеряются в радианах.

Протестировано для работы в Firefox и Chrome. Не реализовано в Internet Explore и iOS (iPads). Попытайтесь запустить его самостоятельно.

После другого ответа, который я нашел, Габриэль Ратенер сделал аналогичный ответ год назад: https://.com/a/24401317/5032384


Это можно сделать с помощью метода сна 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)

Где 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.







sleep