Promises(承诺)是JavaScript中处理异步操作的一种机制,它提供了一种更优雅和可读性更高的方式来处理异步代码。Promises的实现原理基于一种称为"Promise/A+"规范的约定,该规范定义了Promises的行为和接口。
Promises的实现原理是什么?
Promises的实现原理可以通过以下4步概括:
- Promise有3种状态:pending、fulfilled和rejected。初始状态为pending。
- Promise实例包含一个then方法,then方法接受两个参数:onFulfilled和onRejected,分别为promise成功或失败的回调。
- Promise有一个内部属性[[PromiseState]],初始值为pending。内部又有一个属性[[PromiseResult]],初始值为undefined。
- Promise的状态只能从pending到fulfilled或rejected,状态一旦改变就不能再变。 fulfilled和rejected状态都会触发then里的回调。
当我们new一个Promise时,会传入一个执行器executor,执行器会立即执行。在执行器中我们可以处理异步任务,比如发送ajax请求,一旦异步任务执行结束,就可以决定是resolve(成功)还是reject(失败)这个promise。
如果执行resolve,那么将[[PromiseState]]设为fulfilled,[[PromiseResult]]设为传入的值。执行onFulfilled回调。
如果执行reject,那么将[[PromiseState]]设为rejected,[[PromiseResult]]设为传入的reason。执行onRejected回调。
这样通过状态和结果的改变,来触发then里不同的回调,从而实现异步流程的控制。
Promise就是通过状态改变来触发回调的,这也是它实现异步编程的基石。
如果在Promise的执行器函数(executor)中不调用resolve或reject, 会怎么样?
如果在Promise的执行器函数(executor)中不调用resolve或reject,通常会导致两个结果:
- Promise对象的状态永远保持pending
Promise对象代表一个异步操作,它的最终状态应该在某个时刻确定下来(fulfilled或rejected)。如果executor函数中不调用resolve或reject,Promise的状态就无法得以确定,会永远处于pending状态。
- then方法指定的回调函数不会被调用
then方法注册的回调函只有在Promise状态确定后才会被调用,如果状态一直是pending,那么then方法的回调函数就永远不会被执行。
所以,如果在executor函数中不调用resolve或reject,就是一个错误的实现,违反了Promise/A+规范。
正确的做法是,在executor函数中,无论异步任务是否成功,都需要在最后调用resolve或者reject,将Promise的状态确定下来,以便触发then方法注册的回调。通常like这样:
new Promise((resolve, reject) => {
// ...做一些异步操作
if(成功) {
resolve(value);
} else {
reject(error);
}
})
所以,不调用resolve/reject,将导致Promise永远pending,然后注册的回调函数也就不会执行。这违反Promise的设计初衷,应该避免这样使用。