ping pong behaviour using deffered

一笑奈何 提交于 2019-12-08 04:19:28

Here's a way to do it:

function go(val, t) {
    var def = $.Deferred();
    setTimeout(function() {
        log(val);
        def.resolve();
    }, t);
    return def.promise();
}

function run(numCycles, values, delay) {
    function next() {
        if (numCycles > 0) {
            go(values[0], delay).then(function() {
                return go(values[1], delay);
            }).then(function() {
                --numCycles;
                next();
            });
        }
    }
    next();
}

run(10, ["ping", "pong"], 500);

Working demo: http://jsfiddle.net/jfriend00/g0Lxm3ws/

Conceptually, here's how this works:

  1. The function go() outputs one message after a timer. It returns a promise that is resolved when the message has been output.
  2. The function run() accepts a number of cycles and an array of two values to alternate between.
  3. The function next() checks to see if there are any more cycles to run and if so, chains two go() operations together and when the last one is done, decrements the number of cycles and then calls next() again.

There are all sorts of issues with your implementation:

  1. A given deferred or promise can only be resolved or rejected once.
  2. $.when() takes a list of promises so $.when($, dfd) is just wrong.
  3. $.when() is not even needed when there is only one promise as you can just use .then() directly on the promise.
  4. Your for loop won't pause between promises so all your "ping" messages will come out immediately and then the "pong" messages will come out later.

FYI, if you want to cycle through an arbitrary array of values, you can do so like this:

function go(val, t) {
    var def = $.Deferred();
    setTimeout(function() {
        log(val);
        def.resolve();
    }, t);
    return def.promise();
}

function run(numCycles, values, delay) {
    function next() {
        if (numCycles > 0) {
            // create initial resolved promise
            // for start of a .reduce() chain
            var d = $.Deferred().resolve().promise();
            values.reduce(function(p, val){
                return p.then(function() {
                    return go(val, delay);
                });
            }, d).then(function() {
                --numCycles;
                next();
            });
        }
    }
    next();
}


run(5, ["tic", "tac", "toe"], 500);

Working demo: http://jsfiddle.net/jfriend00/1ckb6sg6/

Utkanos

I must say I've no idea how you've arrived at that sort of code or what you're really trying to achieve. However, to at least answer the first of your questions (what's going wrong?):

  • Once a deferred is resolved, it cannot (I believe) later be rejected. They are intended as one-time-use objects, as discussed in this question.

  • Secondly, you are getting all the pings before the pongs because the mechanism by which the pings are output is a synchronous one (the loop). The mechanism by which the pongs are output, however, is an asynchronous one - the timeout. In effective terms, therefore, the pings are all output in the same procedural instance, whereas the pongs don't kick in till 3 seconds later - long after the pings have been output.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!