1

我有一个 javascript 应用程序将所有数据保存在服务器上,然后使用 REST API 通信服务器和客户端。

它们工作正常,直到我们开始有越来越多的嵌套异步调用或隐藏异步调用的嵌套同步调用。例如:

function asyncFoo(callback) {
  callback();
}

function syncCallHidingAsyncCall(){
  syncStuff();
  asyncFoo(function(){
    syncFoo()
  });
}

function nestedAsyncCall(callback){
  asyncFoo(function(){
    anotherAsyncCall(callback);
  })
}
// this make refactor code become so hard.
// if we want add step2() after nestedAsyncCall();
// instead of add one line of code
// we need first add callback param in every asyncCall, then pass step2 as a callback

还有一些不必要的异步调用:

// we actually only verify this once.
function isLogin(callback){
  if (!App._user) {
    ServerApi.getCurUser(function(data){
      App._user = data.user;
      callback(App._user)
    });
  }
  callback(App._user)
}

function syncCallNeedVerfifyLogin(callback){
  // user only need login once, so in most case this is really only a sync call.
  // but now I have to involve a unnecessary callback to get the return value
  isLogin(function(){
    callback(syncStuff())
  })
}

所以随着项目越来越大,我们就开始忘记了他们的关系,哪个需要等待,哪个会变魔术。越来越多的功能变得异步只是因为一些非常小的东西需要在服务器上进行验证。

所以我开始觉得他们一定是这个项目中的一些设计问题。我正在寻找最佳实践或设计模式,或者在这种繁重的通信应用程序中需要遵循一些规则。

感谢帮助。

4

3 回答 3

4

它们以多种模式存在,用于管理异步数据交换和例程执行。它们也有不同的名称:

  • 承诺
  • 事件发射器
  • 延迟对象/延迟
  • 控制流库
  • 期货
  • 回调聚合器
  • 观察者/发布者-订阅者

一个常见的实现是jQuery 的延迟对象,它也用于管理它的 AJAX 方法。在 NodeJS 中,还有AsyncJS和原生EventEmitter。甚至还有一个 20 行库,由某个实现 EventEmitter 的人制作,您可以使用它。

于 2013-04-22T23:37:18.393 回答
0

正如Bergi 在评论中所说,您正在寻找的模式称为延迟/承诺。jQuery 内置了一个实现。从文档:

通过调用 jQuery.Deferred() 方法创建的可链接实用程序对象。它可以将多个回调注册到回调队列中,调用回调队列,并中继任何同步或异步函数的成功或失败状态。

还有各种其他实现,其中一些在此stackoverflow问题中进行了概述。

于 2013-04-22T23:36:29.283 回答
0

让自己成为一个队列系统,例如:

function Queue() {
    this.queue = [];
}
Queue.prototype.i = -1;
Queue.prototype.add = function(fn) {
    if (typeof fn !== "function")
        throw new TypeError("Invalid argument");

    this.queue.push(fn);
}
Queue.prototype.next = function() {
    this.i++;
    if (this.i < this.queue.length) {
        this.queue[this.i].appy(this, arguments);
    }
}
Queue.prototype.start = function() {
    if (this.i !== -1)
        throw new Error("Already running")
    this.next.apply(this, arguments);
}

并像这样使用它:

var q = new Queue();

q.add(function() {
    // do something async
    // In the callback, call `this.next()`, passing
    //    any relevant arguments
})
q.add(function() {
    // do something async
    // In the callback, call `this.next()`, passing
    //    any relevant arguments
})
q.add(function() {
    // do something async
    // In the callback, call `this.next()`, passing
    //    any relevant arguments
})

q.start();

演示:http: //jsfiddle.net/4n3kH/

于 2013-04-22T23:46:06.717 回答