深入理解Promise
Promise 的含义
Promise 是异步编程的一种解决方案。它最早由社区提出并实现,ES6 将它写入了标准,提供原生 Promise
对象成为统一标准。
可以把 Promise 理解成一个容器,里面存放了一个未来才会结束的事件(通常是异步操作)的结果。从语法上说,Promise 是一个对象,它提供统一的 API,可以获取异步操作的结果。
Promise 有两个特点:
- 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:
pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态。 - 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变只有两种可能:从
pending
变成fulfilled
和从pending
变成rejected
。只要这两种情况发生,状态就冻结了,不会再变了。
如果 Promise 返回了成功的信息,那么你在绑在定成功事件上的回调就会得到这个消息。 如果发生了错误,你绑定在错误事件上的回调或捕获错误的回调会得到这个信息。
Promise 解决了什么问题
首先我个人并不认为 Promise 的出现彻底解决了"回调地狱"的问题,因为 Promise 并没有移除回调函数。 那 Promise 究竟解决了什么问题呢?我们不妨先回想下,在 Promise 出现之前,我们通过回调函数控制异步流程的方式是怎么样的。用 axios 举例:
$.axios({
method: 'GET',
url: '/xxx',
success: function (res) {
...
}
})
上面我们使用 axios 发送一个 get 请求,通过 success 字段定义了该请求成功之后的回调函数,试问如果你从没有使用过 axios,你知道请求失败的回调函数要怎么注册吗? 其实这就是我想表达的程序的控制权问题,在 Promise 出现之前,通常是由第三方库传递回调来转移控制权的,你需要根据第三方库的规则去注册回调函数,如果你的项目引入了多个第三方库,而这几个第三方库的定义又不同时,这其实就造成了阅读和可维护性上的障碍。 而 Promise 的出现则解决了上述的问题,并且 Promise 被写入了标准,更加安全可靠。这是 JavaScript 种异步流程控制表达上一个很大的进步。
Promise 的缺点
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数 Promise 内部抛出的错误,不会反应到外部。
- 当处于 pending 状态时,无法得知目前进展到哪一个阶段(是刚开始还是即将完成)。