在JavaScript中的可链接,基于Promise的类接口 [英] Chainable, Promise-based Class Interfaces in JavaScript

查看:224
本文介绍了在JavaScript中的可链接,基于Promise的类接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  function WhizBang(){

var promise;

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

promise = asyncInit();
}

因此,调用 new WhizBang c $ c>将启动 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() musn't,直到 asyncInit()已关闭。并调用 publicMethod_Two(),直到 asyncInit()



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



我想我需要做的是定义一个类,其公共方法都等效于在promise上调用 then(),接着是类特定的,



(使用 Bluebird Promise Library 。)

解决方案

你现在有什么



你现在的感觉真的很不错。因为你在promise中缓存 asyncInit 的结果,每个人都等待同样的承诺 - 这些函数中的任何代码都不可能在promise完成之前运行。

  function publicMethod_One(){
promise //你以`promise.`开头的事实意味着将等待
.then(doStuff)
.catch(reportInitFailure);
}

因此,不是迫使人们等待使用 publicMethod_One ,他们已经可以立即调用, doStuff 的方法只会执行promise已解决。



一个流体接口



好吧,你注意到你的代码有一个大问题,给定的方法没有办法知道什么时候运行或者一种排序方法 - 您可以通过两种方式解决此问题:




  • 创建一个流体接口,返回





让我们看看这两种方法:



流体接口



你的方法返回的实例,他们也必须排队,所以事情不会发生一次。我们可以通过在每次调用时修改 promise 来实现这一点:

  function publicMethod_One (){
promise = promise //注意我们改变它
.then(doStuff)
.catch(reportInitFailure);
return this; //并返回`this`
}

c $ c> .ready 方法返回当前promise,以便可以从外部等待操作顺序:

  function ready(){
return this.promise;
}

这可以启用以下功能:

  var ready = new WhizBang()。publicMethod_One()。publicMethod_One()。ready(); 
ready.then(function(){
// whizbang完成所有操作
}); //也可以添加错误处理程序



返回then



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

  function publicMethod_One(){
return promise //注意我们正在返回而不改变它
.then(doStuff)
.catch(reportInitFailure);
}

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



链接是可能的,因为您使用蓝鸟与 .bind

  var whiz = new WhizBang(); 
var res = Promise.bind(whiz).then(whiz.publicMethod_one)
.then(whiz.publicMethod_one);
res.then(function(){
//所有动作完成,也可以使用更容易的返回值
});

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


I am writing a constructor in JavaScript that has the following properties:

function WhizBang() {

   var promise;

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

   promise = asyncInit();
}

So, calling new WhizBang() will start the asyncInit() process. What isn't obvious from the code above is that none of the public methods in the interface should run until this call to asyncInit() has closed.

So, the definition of publicMethod_One() might look something like this:

function publicMethod_One() {

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

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

Some of the things that happen in doStuff() are asynchronous; some of them aren't.

So, if an end user of my class did something like this:

function main() {

  var whizBang = new WhizBang();

  whizBang
    .publicMethod_One()
    .publicMethod_Two()
  ;
}

The call to publicMethod_One() musn't be made until asyncInit() has closed. And the call to publicMethod_Two() musn't be made until both asyncInit() and publicMethod_One() have closed.

How can I define my class methods so that they are chainable?

What I think I need to do is define a class whose public methods are all equivalent to calling then() on a promise, followed by class specific, implementation stuff.

Internets, halp!

( Bonus points for using the Bluebird Promise Library in your answer. )

解决方案

What you have now

What you have now is actually pretty nice. Since you're caching the result of asyncInit in a promise and everyone waits for the same promise - it's impossible for any of the code in those functions to run before the promise has finished.

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

So rather than forcing people to wait in order to use publicMethod_One they already can call it right away and the methods like doStuff will only execute the promise has resolved.

A fluid interface

Well, like you noticed your code has a major issue, there is no way for a given method to know when to run or a way to sequence methods - you can solve this in two ways:

  • Create a fluid interface that returns this on every action and queues the promise.
  • Return the promise from each async call.

Let's look at the two approaches:

Fluid interface

This means that all your methods return the instance, they must also queue so things don't happen 'at once'. We can accomplish this by modifying promise on each call:

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

You might also want to expose a .ready method that returns the current promise so the sequence of operations can be waited for from the outside:

function ready(){
    return this.promise;
}

This can enable things like:

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

Returning thenables

In my opinion this is the simpler approach, all your methods return the promise they create so they can individually be waited for:

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

This is nice because the async operation is exposed outside.

Chaining is possible since you're using bluebird with .bind as such:

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

But the advantage is it easier to reason about from the outside - for this reason I prefer this approach personally. Personally I always prefer to return meaningful data than to change internal state.

这篇关于在JavaScript中的可链接,基于Promise的类接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆