使用延迟的乒乓行为

时间:2014-11-01 17:11:33

标签: javascript jquery synchronization promise

我创建了以下javascript代码:

var index, _i;

var dfd = new $.Deferred();
dfd.resolve();
for (index = _i = 0; _i < 10; index = ++_i) {
  $.when($, dfd).done(function() {
      console.log('ping');
      promise = (function(index) {
            setTimeout(function() {        
              console.log('pong');
              dfd.resolve();
            }, 3000);     
        dfd.reject();      
      })(index);
  })  
}
在控制台中

我看到以下结果

ping
ping
ping
ping
ping
ping
ping
ping
ping
ping
pong
pong
pong
pong
pong
pong
pong
pong
pong
pong

但我想实现

ping
pong
ping
pong
....

我在哪里错了以及如何根据我想要的行为重写代码?

2 个答案:

答案 0 :(得分:2)

这是一种方法:

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

工作演示:http://jsfiddle.net/jfriend00/g0Lxm3ws/

从概念上讲,这是如何运作的:

  1. 函数go()在计时器后输出一条消息。它返回一个在输出消息时解析的promise。
  2. 函数run()接受多个循环和一个由两个值组成的数组,以便在它们之间交替。
  3. 函数next()检查是否还有更多周期要运行,如果是,则将两个go()个操作链接在一起,当最后一个操作完成时,减少周期数,然后调用再次next()

  4. 您的实施存在各种问题:

    1. 给定的延期或承诺只能解决或拒绝一次。
    2. $.when()会收到一份承诺清单,因此$.when($, dfd)是错误的。
    3. 当只有一个承诺时,甚至不需要
    4. $.when(),因为您可以直接在承诺上使用.then()
    5. 您的for循环不会在承诺之间暂停,因此所有"ping"条消息都会立即显示,然后"pong"消息会在稍后发布。

    6. 仅供参考,如果你想循环一个任意数组的值,你可以这样做:

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

      工作演示:http://jsfiddle.net/jfriend00/1ckb6sg6/

答案 1 :(得分:1)

我必须说我不知道​​你是如何得到这种代码或者你真正想要实现的。但是,至少回答你的第一个问题(出了什么问题?):

  • 一旦延期解决,以后就不会(我相信)被拒绝。它们旨在作为一次性使用对象,如this question中所述。

  • 其次,你在pongs之前得到所有的ping,因为ping的输出机制是同步的(循环)。然而,输出拨弦的机制是异步的 - 超时。因此,在有效的条件下,ping都是在相同的程序实例中输出的,而在3秒之后 - 在输出ping之后很长时间内,它不会启动。