检查回调是否上次被触发的方法?

时间:2014-01-31 21:11:07

标签: javascript

我目前有一个看起来像这样的功能:

function update() {
    buildUpdate(function(result) {
        // send result to clients
    });
}

这通常可以正常工作。但是,如果我这样做:

// data state 1

update(); // this time, buildUpdate() won't take a long time

// do some work resulting in:
// data state 2

update(); // this time, buildUpdate() will take a long time
          // and thus will finish after the third call

// do some work resulting in:
// data state 3

update(); // this time, buildUpdate() won't take a long time

正如预期的那样,客户将收到三个更新。但是它们的顺序错误,因为update()的第三次调用确实早于第二次调用。从客户的角度来看,它看起来像这样:

  • 接收基于数据状态1计算的更新
  • 接收基于数据状态3计算的更新
  • 接收基于数据状态2计算的更新(不应发送此更新)

是否有任何设计模式或功能有助于避免这种情况?

注意:如果客户端未收到所有更新,则无关紧要。重要的只是收到的最后一个必须与当前数据状态一致。

我的想法是在update()每次调用时生成一个随机ID。然后我检查回调它的ID是否与生成的最后一个ID匹配。然而,ID本身的生成引入了新的异步计算,并在每次使用时产生了更多的代码。

2 个答案:

答案 0 :(得分:3)

最简单的可能是添加回调

function update(callback) {
    buildUpdate(function(result) {
        // send result to clients

        if (typeof callback == 'function') callback();
    });
}

并做

 update(function() {           // when the first one finishes
     update(function() {       // run the second one
         update(function() {   // and when the second is finished, the third
              update();        // and so on....
         });
     });
 });

如果添加async中间件,则可以使用更高级的方法来处理异步行为。

答案 1 :(得分:0)

我目前的方法有效,但可能不是最好的解决方案。 如果您有更好的方法,请提交答案。

var outdated = function(f, cb) {
    var counter = 0;
    var finished = -1;
    return function() {
        var no = counter++;
        a = [].slice.call(arguments);
        a.unshift(function() {
            if(no > finished) {
                finished = no;
                cb.apply(this, arguments);
            }
        });
        f.apply(this, a);
    };
};

让我们考虑以下示例:

var example = outdated(function(cb, a) {
    setTimeout(function() {
        cb(a);
    }, a * 1000);
}, function(c) {
    console.log('finished '+c);
});

example(1);
example(4);
example(2);

这将产生以下输出:

finished 1
finished 2

finished 4未在finished 2之前调用,但在之后结束。

要解决问题中所述的实际问题,我会调用这样的函数:

var update = outdated(buildUpdate, function(result) {
    // send update to clients
});

update();
// do some changes
update();