上一篇文章介绍了promise的概念作用及API,这里我们就手鲁代码实现promise
Promise的几个关键问题
开始之前来个灵魂拷问,可能面试会问哟,把这些问题都想清楚是写出promise的关键!!!
1.如何改变 promise 的状态?
改变promise的状态只有3个方法
(1)resolve(value):promiseState pending变成resolved
(2) reject(reason):promiseState pending变成rejected
(3) throw err(抛出异常) promiseState pending变成rejected
2.一个 promise 指定多个成功/失败回调函数, 都会调用吗?
当promise改变对应状态时,都会调用,改变状态后,多个回调函数都会被调用,并不会自动停止
let p = new Promise((resolve, reject) => { resolve('OK');});
///指定回调 - 1
p.then(value => { console.log(value); }); //返回undefined,状态变为resolved
//指定回调 - 2
p.then(value => { alert(value);});
3.改变promise状态和指定回调函数谁先谁后?
都有可能[由同步异步决定]
先指定回调再改变状态(异步):先指定回调--> 再改变状态 -->改变状态后才进入异步队列执行回调函数
先改状态再指定回调(同步):改变状态 -->指定回调 并马上执行回调
let p = new Promise((resolve, reject) => {
//异步写法,这样写会先指定回调,再改变状态
setTimeout(() => {resolve('OK'); }, 1000);
//这是同步写法,这样写会先改变状态,再指定回调
resolve('OK');
});
p.then(value => {console.log(value);}, reason => {})
4.promise.then()返回的新promise的结果状态是什么?
由then()指定的回调函数执行的结果决定
① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
5.promise.catch的异常穿透
当使用promise的then链式调用时,可以在最后指定失败的回调,前面任何操作出了异常,都会传到最后失败的回调中处理
注可以在每一个then的第二个回调函数中进行err处理,也可以利用catch的异常穿透特性,在最后用catch去统一处理,两者一起使用时,,err会生效(因为err已经将其处理,就不会再往下穿透),而走不到后面的catch
7.如何中断promise链
我们知道当promise状态改变时,它的链式调用都会生效
如果我们有一个需求:执行到第二个then的时候中断链式调用,如何中断?
在第二个then回调函数中返回一个pedding状态的promise即可
<script>
let p = new Promise((resolve, reject) => {setTimeout(() => { resolve('OK');}, 1000);});
p.then(value =>{return value})
.then(value => {return new Promise(() => {});})//有且只有这一个方式
.then(value => { console.log(333);})
.catch(reason => {console.warn(reason);});
</script>
手写Promise实现以上功能点
// executor 执行器函数,2个参数,执行器函数是同步调用都
function Promise(executor){
// 2个属性
this.promiseState = 'pending'
this.promiseResult = null
//存放then方法的回调函数
this.callback = []
const resolve = (data) => {
if(this.promiseState === 'pending'){
//修改对象的状态
this.promiseState = 'fullfilled' //也叫resolved
//设置对象结果
this.promiseResult = data
//异步执行,同步任务执行完成后才执行,这里用宏任务模拟了(有些问题)
setTimeout(() => {
this.callback.forEach(item => {
//状态改变调用,并将结果传入
item.onResolved(data)
})
})
}
}
const reject = (data)=>{
//该条件表示状态只能从pending变为rejected
if(this.promiseState === 'pending'){
//修改对象的状态
this.promiseState = 'rejected'
//设置对象结果
this.promiseResult = data
//异步执行,同步任务执行完成后才执行,这里用宏任务模拟了(有些问题)
setTimeout(() => {
this.callback.forEach(item => {
//状态改变调用,并将结果传入
item.onRejected(data)
});
})
}
}
// try..catch处理throw异常的情况
try{
executor(resolve,reject)
}catch(e){
//修改promise对象的状态为rejected
reject(e)
}
}
Promise.prototype.then = function(onResolved,onRejected){
//判断回调函数参数,如果不是函数设置默认函数值
if (typeof onResolved !== 'function') {
onResolved = value => value;
}
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
//返回一个新的promise实例
return new Promise((resolve,reject) =>{
//type为onResolved||onRejected
const detalCallback = (type) => {
try{
// 获取回调函数的执行结果
let result = type(this.promiseResult)
// 判断类型
//如果是Promise类型的对象将其自身的状态赋予外层的promise,即将回调函数执行的promise值及状态赋值给外部的promise
//也就是最终当前then的返回状态由里面回调中的promise的状态决定
if(result instanceof Promise){
result.then(v=>resolve(v),r=>reject(r))
}else{
resolve(result)
}
}catch(e){
//异常,将状态设置为失败
reject(e)
}
}
//判断promiseState的状态,状态为rejected的时候调用onRejected,为fullfilled的时候调用onResolved
if(this.promiseState === 'fullfilled') {
//then 的执行时机在同步任务执行完成后,这里用宏任务完成(存在问题,promise真实的时微任务)
setTimeout(()=>{
detalCallback(onResolved)
})
}
if(this.promiseState === 'rejected') {
setTimeout(()=> {
detalCallback(onRejected)
})
}
if(this.promiseState === 'pending'){
//异步的时候,pending状态没变,不能调用回调函数,此时将回调函数存入实例对象的属性中,在resolve和reject函数中调用
this.callback.push({
onResolved:() => detalCallback(onResolved),
onRejected:() => detalCallback(onRejected)
})
}
})
}
Promise.prototype.catch = function(onRejected){
//ca tch函数为then函数的特例,第一个参数为undefined或者null
return this.then(undefined,onRejected)
}
//静态方法,直接挂载到构造函数上,将对象等转化为Promise,参数是promise时,返回的是内层promise的状态和结果
Promise.resolve = (value)=>{
// 判断传入的参数是否为promise对象
// 1-如果是promise对象:将其状态和结果赋值给外层的promise
// 2,如果为非promise:状态设置为成功
return new Promise((resolve,reject) => {
if(value instanceof Promise){
value.then(v=>resolve(v),r=>reject(r))
}else{
resolve(value)
}
})
}
//不同于resolve方法,该方法只需要把传入 参数再次传出,并将状态改为失败
Promise.reject = (reason)=>{
return new Promise((resolve,reject)=>{
reject(reason)
})
}
//传入promise数组,
//1.每当遍历结果是成功时,用计数器记录,当计数器当值等于数组长度,则全部成功,返回成功状态
//2.如果当数组中任意一个promise的执行结果是rejected时,直接返回失败的状态
Promise.all = (promises)=>{
return new Promise((resolve,reject) => {
//计数器
let count = 0
//存放结果
let arr = []
for(let i = 0; i < promises.length; i++ ){
promises[i].then(v=>{
count++
arr[i] = v
if(count === promises.length){
resolve(arr)
}
},r=>reject(r))
}
})
}
//谁先执行完就返回谁的结果和状态,参数也是promise组成的数组
Promise.race = (promises)=>{
return new Promise((resolve,reject) => {
for(let i = 0; i < promises; i++){
promises[i].then(v => {
//谁的回调先执行就先返回谁
resolve(v)
},
r=>reject(r))
}
})
}
学艺不精,有问题请多多指教