문제

I'm using Q in a to do some jQuery sequental processing of some lines of text (demo). Now I have added a pause button to temporarily halt the processing inside a forEach loop, but if I add a promise.delay(300) inside a while-loop (see partial code below) my browser hangs. How can I implement a conditional pause on the boolean isPaused in a forEach loop using Q?

var promise = new Q();

promise = promise.then(function () {
    lines.forEach(function (item) {

        // Browser starts to hang here if isPaused == true
        promise = promise.then(function () {
            while (isPaused) {
                promise = promise.delay(300);
            }
        });

        // The following does not work either
        // while (isPaused) {
        //  promise = promise.delay(300);
        //}


        // The following does not work either
        // while (isPaused) {
        //  Q.delay(300);
        //}

        if (item[0] == '%') {
            promise = promise.then(function ()
            { return addPrompt(wnd); })
            promise = promise.then(function ()
            { return addInput(item.substr(1)); })
        }
        else {
            promise = promise.then(function ()
            { return addOutput(item, wnd); })
        }
    });
    promise = promise.then(function ()
    { return addPrompt(wnd); })
});
promise.done();
도움이 되었습니까?

해결책

Promises are still asynchronous in this case. The loop in the while(true) will keep executing and no other code will run in the meanwhile.

You simply can not have while(condition) { /* block that does not change 'condition' /* } in plain old browser JavaScript. The code that changes isPaused in your case will never get the chance to execute. (well, you can with ES6 generators that let you explicitly yield control, but that's OT here).

You need to recurse chain the promises instead.

promise = promise.then(function pollUntil(){
     return Q.delay(300).then(function(){
         // recursively chain the continuation here this will check every 300 ms
         // rather than freeze the code.
         return isPaused ? pollUntil() : true; 
     });
});

This reads as: Continue the current action with pollUntil, which delays for 300 miliseconds, and then repeats (calls itself) until isPaused is no longer true.

Note, you can not add .then to the external promise, since you (or might need to in the more general case) chain to it later.

Of course it would be preferable to create a pause() promise that will resolve when you're no longer paused.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top