简体   繁体   English

Javascript:抛出异步链接方法

[英]Javascript: Throw in async chained methods

I've got a class that returns several methods to be chained like this: 我有一个类返回几个链接的方法,如下所示:

class MyClass{
  foo(){
    if(condition) return this;
    else throw;
  }

  bar(){
    if(condition) return this;
    else throw;
  }
}

Conditions are certain checks that may be true or false depending on the internal state of the class 条件是某些检查可能是真或假,取决于类的内部状态

The idea is that I can execute several methods like this: 我的想法是我可以执行以下几种方法:

myInstance.foo().bar();

This way, if any of the conditions in any method fails, this statement will throw an error. 这样,如果任何方法中的任何条件都失败,则此语句将引发错误。

However, now I'm trying to check conditions that require a promise to be resolved: 但是,现在我正在尝试检查需要解决的承诺的条件:

class MyClass2{
  asynCheck(){
     myPromise.then((condition)=>{
        ... // returning a promise won't work
     });

I want to maintain the same syntax as before (adding an await/then), I don't mind changing foo and bar to be async as well, as long as the following syntax is valid: 我想保持与以前相同的语法(添加await / then),我不介意将foo和bar改为异步,只要以下语法有效:

await myInstance.foo().asyncCheck().bar();

Is there a way of doing this? 有办法做到这一点吗? Note that there may be more than one asyncCheck and may be called in any order 请注意,可能有多个asyncCheck,可以按任何顺序调用

You can maybe do it with some major hacks... 你可以用一些主要的黑客来做这件事......

 class MyClass { foo() { const ret = new Promise((resolve, reject) => { resolve(1); }) ret.bar = this.bar.bind(this); return ret; } bar() { const ret = new Promise((resolve, reject) => { resolve(2); }) // hack `ret` to copy the methods over... return ret; } } (async() => { const c = new MyClass; console.log(await c.foo()) console.log(await c.foo().bar()) })() 

You could achieve this using an internal Promise field and reassigning it each time you call a method: 您可以使用内部Promise字段实现此目的,并在每次调用方法时重新分配它:

 class MyClass { constructor(promise) { if (!promise) this.promise = Promise.resolve(); else this.promise = promise; } foo(condition) { this.promise = this.promise.then(() => { console.log("foo"); if (!condition) throw 'foo error'; }); return this; } bar(condition) { this.promise = this.promise.then(() => { console.log("bar"); if (!condition) throw 'bar error'; }); return this; } asynCheck(conditionPromise) { this.promise = this.promise.then(() => { return conditionPromise.then(condition => { console.log("asynCheck"); if (!condition) throw 'asynCheck error'; }); }); return this; } catch(callback) { this.promise.catch(callback); } } let instance = new MyClass(); instance.foo(true) .asynCheck(new Promise((res, rej) => setTimeout(() => res(true), 2000))) .bar(true) .asynCheck(new Promise((res, rej) => setTimeout(() => res(false), 3000))) .foo(false) .catch(e => console.log(e)); 

After a lot of testing, I found a possible solution extending the class with Promise, ending up with something like this: 经过大量测试后,我找到了一个可能的解决方案,用Promise扩展了类,结果是这样的:

class MyClass extends Promise {
  constructor(executor){
    super((resolve, reject)=>{return executor(resolve,reject)});
  }
  foo(){
    return new MyClass((resolve, reject)=>{
      this.then(()=>{
        if(condition) resolve();
        else reject();
      }).catch(()=> reject());
    })
  }

  asyncCheck(){
    return new MyClass((resolve, reject)=>{
      this.then(()=>{
         asyncCondition.then((condition)=>{
             if(condition) resolve();
             else reject();
         });
      }).catch(()=> reject());
    })
  }
}
const bar=new MyClass((r)=>{r()});
await bar.foo().asyncCheck();

The main tradeoff is that the constructor requires a dummy callback due to how extending promises work. 主要的权衡是构造函数需要一个虚拟回调,因为扩展的promises如何工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM