3

我正在用 JavaScript 编写一个具有以下属性的构造函数:

function WhizBang() {

   var promise;

   this.publicMethod_One = function publicMethod_One() { ... };
   this.publicMethod_Two = function publicMethod_Two() { ... };

   promise = asyncInit();
}

因此,调用new WhizBang()将启动该asyncInit()过程。从上面的代码中不明显的是,在此调用asyncInit()关闭之前,接口中的任何公共方法都不应该运行。

因此, 的定义publicMethod_One()可能如下所示:

function publicMethod_One() {

  promise
    .then( doStuff )
    .catch( reportInitFailure )
  ;

  function doStuff() { ... }
  function reportInitFailure() { ... }
}

发生的一些事情doStuff()是异步的;其中一些不是。

所以,如果我班的最终用户做了这样的事情:

function main() {

  var whizBang = new WhizBang();

  whizBang
    .publicMethod_One()
    .publicMethod_Two()
  ;
}

在关闭publicMethod_One()之前不得拨打电话。asyncInit()并且在publicMethod_Two()两者都关闭之前不得asyncInit()拨打publicMethod_One()电话。

如何定义我的类方法以便它们是可链接的?

我认为我需要做的是定义一个类,其公共方法都等同于调用then()一个承诺,然后是特定于类的实现内容。

互联网,停!

(在您的答案中使用Bluebird Promise Library的奖励积分。)

4

1 回答 1

4

你现在拥有的

你现在拥有的其实很不错。由于您将结果缓存asyncInit在一个承诺中并且每个人都在等待相同的承诺 - 这些函数中的任何代码都不可能在承诺完成之前运行。

function publicMethod_One() {    
  promise // the fact you're starting with `promise.` means it'll wait
    .then( doStuff )
    .catch( reportInitFailure );
}

因此,与其强迫人们等待才能使用publicMethod_One,他们已经可以立即调用它,并且诸如doStuff只会执行已解决的承诺之类的方法。

流体界面

好吧,就像您注意到您的代码有一个主要问题一样,给定的方法无法知道何时运行或对方法进行排序 - 您可以通过两种方式解决这个问题:

  • 创建一个流畅的界面,this在每个动作上返回并将承诺排队。
  • 从每个异步调用中返回承诺。

让我们看看这两种方法:

流体界面

这意味着您的所有方法都返回实例,它们还必须排队,这样事情就不会“立即”发生。我们可以通过修改promise每个调用来完成此操作:

function publicMethod_One() {    
  promise = promise // note we're changing it
    .then( doStuff )
    .catch( reportInitFailure );
  return this; // and returning `this`
}

您可能还想公开一个.ready返回当前承诺的方法,以便可以从外部等待操作序列:

function ready(){
    return this.promise;
}

这可以启用以下功能:

var ready = new WhizBang().publicMethod_One().publicMethod_One().ready();
ready.then(function(){
     // whizbang finished all operations
}); // can also add error handler

返回 thenables

在我看来,这是更简单的方法,您的所有方法都返回它们创建的承诺,因此可以单独等待它们:

function publicMethod_One() {    
  return promise // note we're returning and not changing it
    .then( doStuff )
    .catch( reportInitFailure );
}

这很好,因为异步操作暴露在外面。

链接是可能的,因为您使用的是 bluebird .bind

var whiz = new WhizBang();
var res = Promise.bind(whiz).then(whiz.publicMethod_one)
                            .then(whiz.publicMethod_one);
res.then(function(){
     // all actions completed, can also use return values easier.
});

但优点是更容易从外部推理——因此我个人更喜欢这种方法。就我个人而言,我总是更喜欢return有意义的数据而不是改变内部状态。

于 2015-02-06T23:02:11.477 回答