关于Javascript Promise你需要知道的5件事

91 阅读4分钟

本文是【前端学英语】系列文章的第一篇,英语对于程序员的重要性已经不用多言,如果你想阅读更多英语类的技术文章,或者你想进入外企,英语对你来说都是必不可少的。我在网上查找了一些前端英语文章,并附上自己的翻译,旨在帮助想提高前端能力和英语能力的读者一些帮助。

Promise pattern is a must for modern JavaScript programming. It looks quite simple with then/catch chaining, but it has some details that we’d better know. This article would bring 5 things to know about Promise.

Promise模式是现代js编程的必备条件。通过使用then/catch链,使它看起来非常简单,但是还是有一些细节我们最好需要知道。这篇文章会介绍5件关于Promise你需要知道的事。

1. Recurring resolve

1、重复resolve

What’s going to happen if the following code runs?

下面这段代码在运行的时候会发生什么?

new Promise(resolve => {
  resolve(new Promise(resolve => {
    resolve(new Promise(resolve => {
      resolve(10)
    }))
  }))
})
.then(value => console.log(value)) // 10

Thethen()gives you10(not a Promise instance). If the resolved value is a Promise, then it resolves until it’s not then-able.

最终then里面会输出10,而不是一个Promise实例。如果resolve的值是一个Promise,那么它会一直往下resolve直到resolve到具体的值

2. Return chaining

2、返回链

The then() chain is not just a function chain but also a value chain.

then链不仅是一个函数链,还是一个值链。例如:

Promise.resolve(10)
  .then(value => value + 1)
  .then(value => value + 1)
  .then(value => console.log(value)) // 12

The firstthen()gives10for the value, the second11, the third12. It also applies the recurring chaing for the returned value so the following code works as the same.

第一个then的value是10,第二个then的value是11,第三个是12。它也对返回值应用了循环链所以下面的代码运行结果是一样的:

Promise.resolve(10)
  .then(value => value + 1)
  .then(value => Promise.resolve(value + 1))
  .then(value => console.log(value)) // 12

3. Second parameter of then()

3、then函数的第二个参数

then() actually takes 2 parameters. The second parameter takes a function to handle the case of reject. It works quite similar with the catch(). The results of the following code are same.

then实际上接收两个参数。第二个参数也是一个函数,用来处理reject的情况,它的效果和catch非常类似。所以下面代码运行结果是一样的:

// then() with second parameter
Promise.reject(10)
  .then(
    value => value + 1,
    reason => handleError(reason), // reason=10
  )
// then() and catch()
Promise.reject(10)
  .then(value => value + 1)
  .catch(reason => handleError(reason)) // reason=10

What if we take both like the below?

那如果我们像下面代码一样把两个都用上会怎样?

Promise.reject(10)
  .then(
    value => value + 1,
    reason => handleError1(reason), // called
  )
  .catch(reason => handleError2(reason)) // not called

If both are given, the second parameter ofthen()is prior tocatch()so handleError1() is called and handleError2() is not. The only exception is the case where the Promise actually throws an error. See the code below.

如果两个都用上的话,then的第二个参数优先级会高于catch,所以handleError1会被调用,handleError2不会。唯一的例外是当Promise抛出错误的时候。比如下面的代码:

new Promise(() => { throw 'error' })
  .then(
    value => value + 1,
    reason => handleError1(reason), // not called
  )
  .catch(reason => handleError2(reason)) // called

It catches the error in thecatch()clause only, so handleError2() is called. An interesting part is that if it does not havecatch(), it throws the error even with the onReject parameter.

这只会在catch中捕获到错误,所以handleError2会被调用。有趣的是如果我们没写catch,即使我们使用了then的第二个参数,它也会抛出错误。

4. Error throw in then()

4、在then中抛出错误

If an error occurs in the then(), it catches in the catch() clause.

如果在then中抛出一个错误,这个错误会在catch中被捕获。

Promise.resolve(10)
  .then(value => { throw 'error' })
  .catch(reason => handleError(reason)) // catch!

5. Error as a value

5、使用Error作为返回值

It sounds interesting if we try to resolve with an Error. Can you imagine what happens with the code below?

resolve一个Error听起来很有趣。你可以想象下面的代码会发生什么吗?

Promise.resolve(new Error('error'))
  .then(value => console.log(value)) // Error value
  .catch(reason => handleError(reason))

It does not catch but resolve normally, so it logs the raw Error. Promise does not give a privilege to the Error but Promise itself.

它不会在catch中被捕获,而是正常的resolve。所以它打印出了Error的值。Promise并没有给Error特权,而是把它当作Promise的一部分。

..and an advice

...一个建议

Promise pattern is useful for handling an async job, yet it usually comes to the curved lines of code with nested Promises. It’s not good to read, so an alternative is to use async/await. Modern JavaScript bundlers provide the transpile of async/await syntax.

Promise模式对处理异步非常有用,但是当使用嵌套的Promise时它通常会出现很多行换行代码。这不便于阅读,所以另一种选择是使用async/await。现代js打包器可以对async/await语法进行转译。