Promise 反模式的坑

140 阅读1分钟

背景

今天花了大半天时间在一个老项目上查找问题,里面有两个由于不熟悉 promise 导致的一些容易出现问题的代码(anti-pettern, 低效待优化的设计模式);

本文主要是展开讲下遇到问题和延伸下其他的 promise 反模式(反模式并没有固定的标准,我只是将自己遇到的反模式和参考文档里面我觉得比较常见的问题进行总结)。

关联文章: web错误处理/错误捕获方案

问题一

不知道大家有没有这样用过 promise :

new Promise(async(resolve, reject) => {
  try{
    await dosomething()
    resolve()
  }catch(err) {
    console.log(err)
  }
})

其实外层的 promise 是冗余的,当使用async...await函数时,相当于在外层套了一个promise(在编译为es5时,也会在generator中套一个promise):

async () => {
  await dosomething()
}

其实在正常运行代码过程中是没有问题的, 但如果 dosomething 这个函数执行出现错误,其实try..catch是无法捕获到错误的。 另,如果开启了eslint推荐模式的话,eslint对这种用法是会报错的。no-async-promise-executor

问题二

promise必须链式的调用,不能中断,e.g.

function dosomething() {
  throw Error('ooooooops!')
}
function fn() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, 3000)
  })
  promise.then(() => {
    dosomething()
  })
  return promise
}
fn().catch(err => {
  console.log(err)
})

其实很奇怪这样的代码是怎么写出来的,但写出来了你又没那么容易看出来问题在哪里...
因为中断了promise, 当 dosomething 出现问题也是无法捕获的。

其他

1、不使用catch;
2、使用async...await替代嵌套式promise;
...

参考文章

1、Common Promise Anti-Patterns and How to Avoid Them: runnable.com/blog/common…
2、将 async/await 编译到 ES3/ES5 (外部帮助库): cloud.tencent.com/developer/a…