JavaScript中的可链接,基于Promise的类接口

时间:2015-02-06 22:06:26

标签: javascript interface constructor promise chainable

我在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()

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

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

互联网,停了!

(在答案中使用Bluebird Promise Library的加分点。)

1 个答案:

答案 0 :(得分: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并对承诺进行排队。
  • 从每次异步调用中返回承诺。

让我们看看这两种方法:

流体界面

这意味着您的所有方法都会返回实例,它们也必须排队,以便不会立即发生事情。#39;我们可以通过在每次调用时修改promise来实现此目的:

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

您可能还希望公开一个返回当前promise的.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

返回theables

在我看来,这是一种更简单的方法,所有方法都会返回他们创建的承诺,以便他们可以单独等待:

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

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

链接是可行的,因为您将{blue}与.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有意义的数据,而不是改变内部状态。