优雅的链式调用 async 方法

2,451 阅读1分钟

前言

最近项目开发的时候遇到了一个问题 -- 如何链式调用 async? (当然不是指的 promise.then().then(), 这种的

举个例子

class A {
  val = 1

  async foo() {
    this.val += 1
    return this
  }
  async bar(x) {
    this.val += x
    return this
  }
}
const a = new A()
// 一般我们会这么去写
const v = await a.foo().then(
  a => a.foo()
).then(
  a => a.bar(10)
).then(
  a => a.val
)
// 或者这么写
const v = (await (
  await a.foo()
).bar(10)).val
// 上面俩种写法感觉都不是很好看,我的目的是想如此去用 stream(chain) 的风格去编写代码
const v = await a
  .foo()
  .bar(10)
  .val

想法

在询问了一位大佬后,看他的源码写了一下

(因为他的那部分代码在处理类的 property 上有一些问题,所以后面放弃了他的库

库用到了下面一些技术(其实还有 ts

  • Proxy
  • Promise

实现

我们可以从第一种写法中得到启发,只要 hack 掉每次的 async method 的返回值,与 Promise 的调用即可

代码花了一半去生成类型,如果对 ts 不感冒,可以直接看下面部分

core 代码

使用

npm install stream-async
# or
yarn add stream-async
  • 简单的 class 示范
import { streamAsync } from 'stream-async'
class A {
  foo = 1
  async asyncFun() {
    this.foo += 1
    return this
  }
}
const a = streamAsync(new A())
a.asyncFun().asyncFun()
console.log(a.foo)
// there will output `3`
  • 稍微有设计感点的写法
import { streamAsync } from 'stream-async'
class A {
  stream = streamAsync(this)
  foo = 1
  fun () {
    this.foo += 1
    return this
  }
  async asyncFun() {
    this.foo += 1
    return this
  }
  async asyncFun0(x) {
    this.foo += x
    return this
  }
}
const a = new A()
a.stream
  .asyncFun()
  .fun()
  .asyncFun()
  .asyncFun0(10)

console.log(a.foo)
// there will output `14`

相关链接

感谢

  • shigma 的帮助, 没有这个仓库,我估计是比较难写的 prochain