Асинхронно задерживать JS, пока не будет выполнено условие - PullRequest
7 голосов
/ 26 сентября 2011

У меня есть класс, ChatRoom, который может отображаться только после получения длинного HTTP-запроса (это может занять 1 или 30 секунд). Поэтому мне нужно отложить рендеринг, пока ChatRoom.json не станет нулевым.

В приведенном ниже коде я использую библиотеку Closure Library goog.async.ConditionalDelay. Это работает, но есть ли лучший способ (возможно, без использования библиотеки закрытия) сделать это?

ChatRoom.prototype.json = null; // received after a long-running HTTP request.

ChatRoom.prototype.render = function() {
    var thisChatRoom = this;

    function onReady() {
        console.log("Received JSON", thisChatRoom.json);
        // Do rendering...
    }

    function onFailure() {
        alert('Sorry, an error occurred. The chat room couldn\'t open');
    }

    function isReady() {
        if (thisChatRoom.json != null) {
            return true;
        }
        console.log("Waiting for chat room JSON...");
        return false;
    }

    // If there is a JSON request in progress, wait until it completes.
    if (isReady()) {
        onReady();
    } else {
        var delay = new goog.async.ConditionalDelay(isReady);
        delay.onSuccess = onReady;
        delay.onFailure = onFailure;
        delay.start(500, 5000);
    }
}

Обратите внимание, что "while (json == null) {}" невозможно, потому что это будет синхронно (блокируя все остальные операции JS).

Ответы [ 3 ]

22 голосов
/ 26 сентября 2011

Учтите это:

(function wait() {
    if ( chatroom.json ) {
        chatroom.render();
    } else {
        setTimeout( wait, 500 );
    }
})();

Это будет проверяться каждые полсекунды.

Демонстрационная версия: http://jsfiddle.net/kBgTx/

1 голос
/ 15 апреля 2019

Этого также можно добиться, используя дебодер Лодаша с рекурсией.

import _debounce from 'lodash/debounce';

const wait = (() => {
    if ( chatroom.json ) {
        chatroom.render();
    } else {
      _debounce(wait, 500)();
    }
})();
0 голосов
/ 08 февраля 2016

Ответ, который я придумал, такой:

var count = 0;
// Number of functions that need to run. This can be dynamically generated
// In this case I call check(data, cb) a total of 3 times
var functionNum = 3; 
function toCallAfter(){
    console.log('I am a delayed function');
}

У меня было это для функции проверки, которая запускалась один раз регулярно и дважды в цикле:

check(data, function(err){ // check is my asynchronous function to check data integrity
    if (err){
        return cb(null, { // cb() is the return function for the containing function
            errCode: 'MISSINGINFO',
            statusCode: 403,
            message : 'All mandatory fields must be filled in'
        });
    } // This part here is an implicit else
    count++; // Increment count each time required functions complete to
             // keep track of how many function have completed
    if (count === functionNum) {
        return anon();
    }
    return;
});
// Run twice more in a loop
for(var i = 0; i < 2; i++) {
    check(data, function(err) { // calls check again in a loop
        if (err){
            return cb(null, {
                errCode: 'MISSINGINFO',
                statusCode: 403,
                message : 'All mandatory fields must be filled in'
            });
        }
        count++;
        if (count === functionNum) {
            return toCallAfter();
        }
        return;
    });
}

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

(function wait() {
    if ( chatroom.json ) {
        chatroom.render();
    } else {
        setTimeout( wait, 500 );
    }
})();

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

...