# promise 的特性、优缺点,内部是如何实现的
# Promise基本特性
Promise
有三种状态:pending
(进行中)、fulfilled
(已成功)、rejected
(已失败)Promise
对象接受一个回调函数作为参数, 该回调函数接受两个参数,分别是成功时的回调resolve
和失败时的回调reject
;另外resolve
的参数除了正常值以外, 还可能是一个Promise
对象的实例;reject
的参数通常是一个Error
对象的实例。then
方法返回一个新的Promise
实例,并接收两个参数onResolved
(fulfilled
状态的回调);onRejected
(rejected
状态的回调,该参数可选)catch
方法返回一个新的Promise
实例finally
方法不管Promise
状态如何都会执行,该方法的回调函数不接受任何参数Promise.all()
方法将多个多个Promise
实例,包装成一个新的Promise
实例,该方法接受一个由Promise
对象组成的数组作为参数(Promise.all()
方法的参数可以不是数组,但必须具有Iterator
接口,且返回的每个成员都是Promise
实例),注意参数中只要有一个实例触发catch
方法,都会触发Promise.all()
方法返回的新的实例的catch
方法,如果参数中的某个实例本身调用了catch
方法,将不会触发Promise.all()
方法返回的新实例的catch
方法Promise.race()
方法的参数与Promise.all
方法一样,参数中的实例只要有一个率先改变状态就会将该实例的状态传给Promise.race()
方法,并将返回值作为Promise.race()
方法产生的Promise
实例的返回值Promise.resolve()
将现有对象转为Promise
对象,如果该方法的参数为一个Promise
对象,Promise.resolve()
将不做任何处理;如果参数thenable
对象(即具有then
方法),Promise.resolve()
将该对象转为Promise
对象并立即执行then
方法;如果参数是一个原始值,或者是一个不具有then
方法的对象,则Promise.resolve
方法返回一个新的Promise
对象,状态为fulfilled
,其参数将会作为then
方法中onResolved
回调函数的参数,如果Promise.resolve
方法不带参数,会直接返回一个fulfilled
状态的Promise
对象。需要注意的是,立即resolve()
的Promise
对象,是在本轮事件循环
(event loop
)的结束时执行,而不是在下一轮事件循环
的开始时。Promise.reject()
同样返回一个新的Promise
对象,状态为rejected
,无论传入任何参数都将作为reject()
的参数
# Promise
优点
- 统一异步
API
Promise
的一个重要优点是它将逐渐被用作浏览器的异步 · ,统一现在各种各样的 · ,以及不兼容的模式和手法。 Promise
与事件对比 和事件相比较,Promise
更适合处理一次性的结果。在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。Promise
的这个优点很自然。但是,不能使用Promise
处理多次触发的事件。链式处理是Promise
的又一优点,但是事件却不能这样链式处理。Promise
与回调对比 解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。Promise
带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 · )。
# Promise
缺点
- 无法取消
Promise
,一旦新建它就会立即执行,无法中途取消。 - 如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部。 - 当处于
Pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 Promise
真正执行回调的时候,定义Promise
那部分实际上已经走完了,所以Promise
的报错堆栈上下文不太友好。
# 简单代码实现 请看手写 promise
# Promise 的关键问题
# 1. 如果改变promise
的状态 ❓
resolve(value)
:如果当前状态为pending
则改变为resolved
。reject(reason)
:如果当前状态为pending
则改变为rejected
。- 抛出异常:如果当前是
pending
则改变为rejected
。
const p = new Promise((resolve, reject) => {
// resolve(1); //成功 promise 改变为resolved状态
// reject(2); //失败 promise 改变为rejected状态
throw new Error('错误'); //抛出异常 同样为失败 rejected状态 reason为抛出的 error
})
console.log(p); // 打印实例对象,看状态
// 抛出其他值
const p = new Promise((resolve, reject) => {
throw 3
})
// 输出结果
p.then(
value => { },
reason => { console.log('reason1'+reason); }
)
# 2. 一个promise
对象指定多个成功或失败回调函数,都会调用吗 ❓
当promise改变为对应状态是都会调用.
// 成功和失败同理
const p = new Promise((resolve, reject) => {
throw 3
})
p.then(
value => { },
reason => { console.log('reason1' + reason); }
)
p.then(
value => { },
reason => { console.log('reason2' + reason); }
)
# 3. 改变promise
状态和执行回调函数,谁先谁后 ❓
都有可能,正常情况下是先指定回调函数在改变状态,但也可以先改变状态再指定回调函数。
如何先改状态再指定回调
在执行器中直接掉用
resolve()
和reject()
方法延迟更长时间再调用
then()
.
// 常规:先指定回调,再改变状态
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1) // 2.后改变的状态(同时指定数据),异步执行回调函数
}, 1000);
}).then( //1.先指定的函数,保存当前指定的回调函数
value => { },
reason => { console.log('reason', reason); })
// 先改状态,再指定回调
// 方法一
new Promise((resolve, reject) => {
resolve(1) // 1.先改变的状态(同时指定数据),异步执行回调函数
}).then( //2.后指定的函数,保存当前指定的回调函数
value => { console.log('value2', value); },
reason => { console.log('reason2', reason); })
// 方法二
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1) // 1.先改变的状态(同时指定数据),异步执行回调函数
}, 1000);
})
setTimeout(() => {
p.then( //2.后指定的函数,保存当前指定的回调函数
value => { console.log('value3', value); },
reason => { console.log('reason3', reason); })
}, 1100);//设置的定时器比上面的异步回调时间长即可
.then
和它里的的回调函数是两回事.then()
会同步执行,但它内部的value=>{}
,reason=>{}
是异步执行的
.then(
value => { console.log('value', value); },
reason => { console.log('reason', reason); })
# 4. promise.then()
返回的新promise
对象的结果状态由什么决定 ❓
new Promise((resolve, reject) => {
// resolve(1)
reject(2)
}).then(
value => {
console.log('onResolved1--' + value); },
reason => {
console.log('onRejcected1--' + reason); }
).then(
value => {
console.log('onResolved2--' + value); },
reason => {
console.log('onRejcected2--' + reason); }
)
// 第一次.then()执行后会返回一个新的promise对象,这个新对象的结果和第一次.then()的结果是成功还是失败相关。
(1)简单表述:由then()
指定的回调函数-执行的结果-决定。
(2)详细表述:
- 如果返回的是另一个新promise,此promise的结果就会变成新promise的结果。
new Promise((resolve, reject) => {
resolve(1) //1. 成功的数据
}).then(
value => {
console.log('onResolved1--' + value);
// 2.没有return 值,默认返回的是 undefined ,
},
reason => {}
).then(//3.下一个.then 是接收的上一个promise对象的结果-的返回值,所以输出的是 undefined
value => {
console.log('onResolved2--' + value); },
reason => {
console.log('onRejcected2--' + reason); }
)
- 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值。
new Promise((resolve, reject) => {
// resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1--' + value);
// return 2 // 直接 return 一个值
// return Promise.resolve(2)//成功状态值为2的Promise对象
// return Promise.reject(2)//失败状态值为3的Promise对象
throw 5
},
reason => {
console.log('onRejcected1--' + reason);
// return Promise.resolve(2)//成功状态值为2的Promise对象
// return Promise.reject(3)//失败状态值为3的Promise对象
throw 5
}
).then(
value => {
console.log('onResolved2--' + value);
},
reason => {
console.log('onRejcected2--' + reason);
}
)
- 如果抛出异常,新promise变为rejected,reason为抛出的异常。
new Promise((resolve, reject) => {
resolve(1)
// reject(2)
}).then(
value => {
console.log('onResolved1--' + value);
// throw 5
throw new Error('err')
},
reason => {
console.log('onRejcected1--' + reason);
}
).then(
value => {
console.log('onResolved2--' + value);
},
reason => {
console.log('onRejcected2--' + reason);// 5 | err
}
)
# 5.Promise如果串联多个操作任务 ❓
- promise的.then()返回一个新promise对象,可以看成then()的链式调用
- 通过.then()的链式调用,串联多个同步或异步任务。
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务1(异步)');
resolve(1)
}, 1000);
}).then(
value => {
console.log('任务一的结果', value);
console.log('执行任务2(同步)');
return 2
},
).then(
value => {
console.log('任务二的结果', value);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务3(异步)');
resolve(3)
}, 1000)
})
}
).then(
value => {
console.log('任务三的结果', value);
})
# 6. Preomise 的异常传透 ❓
- 当使用promise的.then()链式调用时,可以在最后指定失败的回调;
- 前面任何操作了异常,都会传到最后失败的回调中处理。
// 例子:失败的状态,但时.then中没有定义 reason=>{}
// 会直接传透到最后的.catch()中。
new Promise((resolve, reject) => {
// resolve(1)
reject(2)
}).then(
value => {
console.log('onResolved', value);
},
).then(
value => {
console.log('onResolved', value);
},
).then(
value => {
console.log('onResolved', value);
},
).catch(
reason => {
console.log('onRejected', reason);
}
)
// 实际内部的操作 reason => { throw reason } or reason => Promise.reject(reason)
new Promise((resolve, reject) => {
// resolve(1)
reject(2)
}).then(
value => {
console.log('onResolved', value);
},
// reason => { throw reason }
// reason => Promise.reject(reason)
).then(
value => {
console.log('onResolved', value);
},
// reason => { throw reason }
// reason => Promise.reject(reason)
).then(
value => {
console.log('onResolved', value);
},
// reason => { throw reason }
// reason => Promise.reject(reason)
).catch(
reason => {
console.log('onRejected', reason);
}
)
# 7. 中断 promise 链
- 当使用promise的.then()链式调用时,在中间中断,不在调用后面的回调函数。
- 办法:在回调函数中返回一个pending状态的promise对象。
new Promise((resolve, reject) => {
// resolve(1)
reject(2)
}).then(
value => {
console.log('onResolved', value);
},
reason => { throw reason }
).then(
value => {
console.log('onResolved', value);
},
reason => { throw reason }
).then(
value => {
console.log('onResolved', value);
},
reason => Promise.reject(reason)
).catch(
reason => {
console.log('onRejected', reason);
// throw reason
// return Promise.reject(reason);
// 没有throw reason 或者 return Promise.reject(reason) 下一个.then()的值是 resolve :undefined ,因为返回值是 undefined
//
// 中断执行链式调用
//返回一个新的状态为pending的promise对象即可
return new Promise(() => { })
}
).then(
value => {
console.log('onResolved2', value);
},
reason => {
console.log('onRejected2', reason);
}
)