Что такое JavaScript-версия sleep ()? - PullRequest
1903 голосов
/ 04 июня 2009

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

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

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

Ответы [ 73 ]

4 голосов
/ 03 декабря 2011

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

/**
 * Netscape compatible WaitForDelay function.
 * You can use it as an alternative to Thread.Sleep() in any major programming language
 * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
 * parameters:
 * (Number) delay in millisecond
 */
function nsWaitForDelay(delay) {
    /**
     * Just uncomment this code if you're building an extention for Firefox.
     * Since FF3, we'll have to ask for user permission to execute XPCOM objects.
     */
    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

    // Get the current thread.
    var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;

    // Create an inner property to be used later as a notifier.
    this.delayed = true;

    /* Call JavaScript setTimeout function
      * to execute this.delayed = false
      * after it finish.
      */
    setTimeout("this.delayed = false;", delay);

    /**
     * Keep looping until this.delayed = false
     */
    while (this.delayed) {
        /**
         * This code will not freeze your browser as it's documented in here:
         * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
         */
        thread.processNextEvent(true);
    }
}
4 голосов
/ 30 июля 2013

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

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
        });
    });
});
3 голосов
/ 10 января 2015

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

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

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

2 голосов
/ 05 августа 2014

Примите асинхронную природу JavaScript!

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

Методы, которые я здесь описал, предназначены для разных случаев использования и примерно упорядочены по сложности.

Различаются следующие вещи:

  • В ожидании выполнения какого-либо условия
  • Ожидание завершения набора методов (в любом порядке) перед вызовом одного обратного вызова
  • Запуск ряда асинхронных методов с общим состоянием в определенном порядке перед вызовом обратного вызова

Подождите

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

Это довольно базовая реализация, предполагающая, что условие в какой-то момент станет истинным. С помощью нескольких настроек его можно расширить, чтобы сделать его еще более полезным (например, путем установки ограничения вызовов). (Я написал это только вчера!)

function waitFor(predicate, successCallback) {
    setTimeout(function () {
        var result = predicate();
        if (result !== undefined)
            successCallback(result);
        else
            waitFor(predicate, successCallback);
    }, 100);
}

телефонный код:

    beforeEach(function (done) {
        selectListField('A field');

        waitFor(function () {
            var availableOptions = stores.scrapeStore(optionStore);
            if (availableOptions.length !== 0)
                return availableOptions;
        }, done);
    });

Здесь я вызываю что-то, что загружает extjs 'store' и ждет, пока в хранилище что-то будет, прежде чем продолжить (beforeEach - это фреймворк для тестирования жасмина).

Подождите, пока завершится несколько вещей

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

createWaitRunner = function (completionCallback) {
    var callback = completionCallback;
    var completionRecord = [];
    var elements = 0;

    function maybeFinish() {
        var done = completionRecord.every(function (element) {
            return element === true
        });

        if (done)
            callback();
    }

    return {
        getNotifier: function (func) {
            func = func || function (){};

            var index = elements++;
            completionRecord[index] = false;

            return function () {
                func.applyTo(arguments);
                completionRecord[index] = true;
                maybeFinish();
            }
        }
    }
};

телефонный код:

    var waiter = createWaitRunner(done);

    filterList.bindStore = waiter.getNotifier();
    includeGrid.reconfigure = waiter.getNotifier(function (store) {
        includeStore = store;
    });
    excludeGrid.reconfigure = waiter.getNotifier(function (store) {
        excludeStore = store;
    });

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

Запуск асинхронных методов в порядке

Я использовал другой подход, когда у меня была серия асинхронных методов для вызова подряд (снова в тестах). Это чем-то похоже на то, что вы можете получить в библиотеке Async - серия делает примерно то же самое, и я сначала немного прочитал эту библиотеку, чтобы посмотреть, получилось ли то, что я хотел. Я думаю, что у меня есть более приятный API для работы с тестами (+ это было интересно реализовать!).

//provides a context for running asyncronous methods syncronously
//the context just provides a way of sharing bits of state
//use run to execute the methods.  These should be methods that take a callback and optionally the context as arguments
//note the callback is provided first so you have the option of just partially applying your function to the arguments you want
//instead of having to wrap even simple functions in another function

//when adding steps you can supply either just a function or a variable name and a function
//if you supply a variable name then the output of the function (which should be passed into the callback) will be written to the context
createSynchronisedRunner = function (doneFunction) {
    var context = {};

    var currentPosition = 0;
    var steps = [];

    //this is the loop. it is triggered again when each method finishes
    var runNext = function () {
        var step = steps[currentPosition];
        step.func.call(null,
                       function (output) {
                           step.outputHandler(output);
                           currentPosition++;

                           if (currentPosition === steps.length)
                               return;

                           runNext();
                       }, context);
    };

    var api = {};

    api.addStep = function (firstArg, secondArg) {
        var assignOutput;
        var func;

        //overloads
        if (secondArg === undefined) {
            assignOutput = function () {
            };
            func = firstArg;
        }
        else {
            var propertyName = firstArg;
            assignOutput = function (output) {
                context[propertyName] = output;
            };
            func = secondArg;
        }

        steps.push({
                       func: func,
                       outputHandler: assignOutput
                   });
    };

    api.run = function (completedAllCallback) {
        completedAllCallback = completedAllCallback || function(){};

        var lastStep = steps[steps.length - 1];
        var currentHandler = lastStep.outputHandler;
        lastStep.outputHandler = function (output) {
            currentHandler(output);
            completedAllCallback(context);
            doneFunction();
        };

        runNext();
    };

    //this is to support more flexible use where you use a done function in a different scope to initialisation
    //eg the done of a test but create in a beforeEach
    api.setDoneCallback = function (done) {
        doneFunction = done;
    };

    return api;
};

телефонный код:

beforeAll(function (done) {
    var runner = createSynchronisedRunner(done);
    runner.addStep('attachmentInformation', testEventService.getAttachmentCalled.partiallyApplyTo('cat eating lots of memory.jpg'));
    runner.addStep('attachment', getAttachment.partiallyApplyTo("cat eating lots of memory.jpg"));
    runner.addStep('noAttachment', getAttachment.partiallyApplyTo("somethingElse.jpg"));
    runner.run(function (context) {
        attachment = context.attachment;
        noAttachment = context.noAttachment;
    });
});

PartiallyApplyTo - это в основном переименованная версия реализации Curry Дуга Крокфорда. Многое из того, с чем я работаю, принимает в качестве последнего аргумента обратный вызов, поэтому простые вызовы можно выполнять, как это, вместо того, чтобы обернуть все с помощью дополнительной функции.

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

2 голосов
/ 05 июня 2014

Если вам нравится совет, чтобы не потерять производительность. setTimeout - ваш ожидаемый sleep. Однако, если вы хотите использовать синтаксис, в котором код «делится на середину» на sleep, мы можем сделать:

sleep=function(tm,fn){
   window.setTimeout(fn,tm);
}

затем выполните следующие функции:

var fnBeforeSleep=function(){

 //All codes before sleep

}  

var fnAfterSleep=function(){

 //All codes after sleep

}  

Тогда:

fnBeforeSleep();
sleep(2000,
fnAfterSleep);

YEP! ٍ синтаксически, это очень близко к:

fnBeforeSleep();
sleep(2000); 
fnAfterSleep();
2 голосов
/ 04 июня 2009

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

2 голосов
/ 04 апреля 2015

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

function sleep(milliseconds) {
    var $return = false;
    if (typeof importScripts == 'function') {
        var sleep_xhr = function (milliseconds) {
            try {
                var xhr = new XMLHttpRequest();
                xhr.open('GET', 'http://128.0.0.1:' + (Math.random() * 100000).toFixed(0) + '/', false);
                xhr.timeout = milliseconds;
                xhr.send();
            } catch (E) {
                // Nothing to do...
            }
        };
        milliseconds = milliseconds | 0;
        if (milliseconds > 0) {
            var start = Date.now();
            while (Date.now() < start + milliseconds) {
                sleep_xhr((start + milliseconds) - Date.now());
            }
            $return = Date.now() - start;
        }
    }
    return $return;
}

Примечание: эта функция работает только на веб-рабочих .

2 голосов
/ 22 января 2015

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

Во многих случаях можно использовать обещания (AJAX запрашивает общее использование). Они позволяют вам делать асинхронные вещи синхронно. Существует также обработка для успеха / неудачи, и они могут быть связаны.

Они являются частью ECMAScript 6, поэтому поддержка браузеров еще не все, в основном, IE не поддерживает их. Также есть библиотека Q для выполнения обещаний.

Ссылка: http://www.html5rocks.com/en/tutorials/es6/promises/

https://github.com/jakearchibald/es6-promise#readme (Shim для старых или браузеров IE)

2 голосов
/ 22 декабря 2016

Это поможет вам.

var reloadAfter = 10; //seconds
var intervalId = setTimeout(function() {
    //code you want to execute after the time waiting
}, reloadAfter * 1000); // 60000 = 60 sec = 1 min
2 голосов
/ 07 апреля 2017

Функция для сна, использующая синхронный вызов, чтобы ОС могла это сделать. Используйте любую команду OS Sleep вам нравится. Он не занят ожиданием в смысле использования процессорного времени.

Я выбрал пинг по несуществующему адресу.

const cp = require('child_process');

function sleep(ms)
{ 
    try{cp.execSync('ping 192.0.2.0 -n 1 -w '+ms);}
    catch(err){}
}

Тест для проверки работоспособности

console.log(Date.now());
console.log(Date.now());
sleep(10000);
console.log(Date.now());
console.log(Date.now());

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

1491575275136
1491575275157

(и через 10 секунд)

1491575285075
1491575285076
...