关于Promise以及你可能不知道的6件事

10次阅读

共计 1761 个字符,预计需要花费 5 分钟才能阅读完成。

前言
Promise 是一个非常简单的概念,即使你没有机会使用 Promise,你也可能阅读过一些关于 Promise 的文章。


什么是 Promise

所谓 Promise,就是一个 对象 ,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个 异步操作),并且这个事件提供统一的 API,可供进一步处理。


Promise 的作用

Promise 的出现主要是解决地狱回调 callback hell 的问题,比如你需要结果需要请求很多个接口,这些接口的参数需要另外那个的接口返回的数据作为依赖,这样就需要我们一层嵌套一层,但是有了 Promise 我们就无需嵌套。


基本的 api

  1. Promise.resolve()
  2. Promise.reject()
  3. Promise.prototype.then()
  4. Promise.prototype.catch()
  5. Promise.all() // 所有的完成
  6. Promise.all([p1,p2,p3])

Promise 的价值在于使得异步代码以一个更可读的风格结构化,而不是因异步函数嵌套显得混乱不堪。接下来接触到 6 个你可能不知道的关于 Promise 的事。


开始列举之前,先看看怎么创建 Promise:

1、then() 返回一个 forked Promise(分叉的 Promise)

先来看下面两段代码有什么不同:



如果你认为这两段代码是等价的那么你可能会因为 promise 仅仅就是一维回调函数的数组。然而这两段代码并不等价,每次调用 then() 都会返回一个 forked promise,因此,在 A 中如果 func1 中抛出异常,func2 一样会执行,在 B 中是 promise 的链式写法 ,操作的是 func1 中返回的 新的 promise`,由于 func1 中抛出异常,这个 promise 被 rejected 了,结果 func2 被跳过不执行了。


2、回调函数应该传递结果

再来看下边的代码会 alert 什么?

是不是误以为会 alert 出 Hello world?但是结果 alert 出来的确实 undefined,原因我上边也提到了,在链式写法上下文中,下一 .then() 里面操作的是上个返回来的 新的 promise。promise 期待你的回调函数或者返回同一个结果,或者返回其他结果但是会被传给下一个回调。


3、只能捕获来自上一级的异常

再再看两段代码有什么不一样:

在 A 中,当第一个 then 抛出异常时,第二个 then 能捕获到该异常,并会弹出 ” 啊哦 抛出错误了 ”。这符合只捕获来自上一级异常的规则。
在 B 中,正确的回调函数和错误的回调函数在同一级,也就是说,尽管在回调中抛出了异常,但是这个异常不会被捕获。事实上,B 中的错误回调只有在 promise 被 rejected 或者 promise 自身抛出一个异常时才会被执行。


4、错误能被恢复

在一个错误毁掉中,如果没有重新抛出错误,promise 会认为你已经恢复了该错误,promise 的状态,会重新转变为resolved, 在下面的栗子中会弹出 i am saved, 是因为第一个 then()中的错误回调函数被注释了没有重新抛出异常,换句话说下一级无法捕获到异常。

Promise 可被视为洋葱的皮层,每一次调用 then 都会被添加一层皮层,每一个皮层表示一个能被处理的状态,在皮层被处理之后,promise 会认为已经修复了错误,并准备进入下一个皮层。


5、Promise 能被暂停

仅仅因为你已经在一个 then() 函数中执行过代码,并不意味着你不能够暂停 promise 去做其他事情。为了暂停当前的 promise,或者要它等待另一个 promise 完成,只需要简单地在 then() 函数中返回另一个 promise。

在上面的代码中,直到新的 promise 的状态是 resolved 解析后,alert 才会显示。如果要在已经存在的异步代码中引入更多的依赖,这是一个很便利的方式。例如,你发现用户会话已经超时了,因此,你可能想要在继续执行后面的代码之前发起第二次登录。


6、resolved 状态的 Promise 不会立即执行

再再再来看最后一个栗子,运行下面代码回弹出什么呢???

第一眼看上去像不像 2,因为 promise 已经是 resolved,then() 会立即执行(同步)。然而,promise 规范要求是所有回调都是异步的,所以 alert 执行时 i 的值还没有被修改,值依旧是 0。


正文完
 0