promise
总结
短小而精悍,我是之前看过一些,然后再试着写,最后再看看完整思路再来修改自身的
不得不说,按照完整思路来写的确实很 nice,一句话总结就是有 1+1>2
的效果,而我自己写的却只能顾及某个功能,尤其是在发现 finally
的一些特性后,我能想到一些实现,可思路太死板了,我都不信原生实现会这么不优雅,于是看了下标准写法,真的是眼前一亮,充分利用了已有套路,只能说我要多刷点算法,多看点原生代码吧
代码
js
class promise {
constructor(executor) {
this.callbacks = [] // 回调
this.status = 'pedding' // pedding resolve reject
this.result = undefined // 结果
const self = this
function resolve(val) {
if (self.status !== 'pedding') return
self.result = val
self.status = 'resolve'
setTimeout(() => {
self.callbacks.forEach((callback) => {
callback.resolveFun()
})
})
}
function reject(val) {
if (self.status !== 'pedding') return
self.result = val
self.status = 'reject'
setTimeout(() => {
self.callbacks.forEach((callback) => {
callback.rejectFun()
})
})
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
/**
* 大致流程:
* 1. 第一次 new promise 且内部 resolve()
* 2. 会更改其状态且将回调放入异步队列,接着执行 then()
* 3. 此时状态为 resolve,将 then 内的成功方法执行放入异步队列,然后返回新的 promise 实例
* 4. 新的 promise 实例的状态依赖于上面的异步结果,所以此时其状态为 pedding
* 5. 所以这个实例在执行完同步事件后,遇到其 then 方法时,会将成功与失败事件都放入回调数组
* 6. 就这样循环下去,直到所有同步队列全部执行完
* 7. 接着执行异步队列,带着状态慢慢解析下去
*/
then(resolveFun, rejectFun) {
// 一开始这两行默认赋值是传递链的精髓,如果不这样,当手动调用的时候只写了其中一个,那么另外一个的信息就传递不下去
resolveFun = typeof resolveFun === 'function' ? resolveFun : (value) => value
rejectFun = typeof rejectFun === 'function' ? rejectFun : (reason) => { throw reason }
const self = this
return new promise((resolve, reject) => {
function callback(fun) {
try {
const res = fun(self.result)
if (res instanceof promise) {
res.then(r => {
resolve(r)
}, e => {
reject(e)
})
} else {
resolve(res)
}
} catch (e) {
reject(e)
}
}
if (self.status === 'resolve') {
setTimeout(() => { callback(resolveFun) })
}
if (self.status === 'reject') {
setTimeout(() => { callback(rejectFun) })
}
if (self.status === 'pedding') {
self.callbacks.push({
resolveFun: () => { callback(resolveFun) },
rejectFun: () => { callback(rejectFun) }
})
}
})
}
catch(rejectFun) {
return this.then(undefined, rejectFun)
}
/**
* 这一块很巧妙
* 经过测试得知 finally 有两个特性
* 1. 本身不接收任何参数
* 2. 内部的 return 以及 新建 promise 链都不会影响下一个 then 的结果
* 只会把上一个 promise 的结果给下一个,只有在自身内部抛出错误时才会将此错误信息传递给下个链
*/
finally(cb) {
return this.then((value) => {
return promise.resolve(cb()).then(() => value)
}, (err) => {
return promise.resolve(cb()).then(() => { throw err })
})
}
static resolve(value) {
return new promise((resolve, reject) => {
if (value instanceof promise) {
value.then(r => {
resolve(r)
}, e => {
reject(e)
})
} else {
resolve(value)
}
})
}
static reject(reason) {
return new promise((resolve, reject) => {
reject(reason)
})
}
/**
* 在写 all、allSettled、any等这些需要遍历 promise 的静态方法时
* 要考虑到无论内部加了多少延迟,输出顺序也要和进来的时候是一样的
* 至于结束的时机就在每个 then 内加计数就行,满足进来时的长度就说明全部执行完了
*/
static all(promises) {
return new promise((resolve, reject) => {
const arr = []
let sum = 0
promises.forEach((pro, index) => {
pro.then((res) => {
sum++
arr[index] = res
if (sum === promises.length) {
resolve(arr)
}
}, (err) => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new promise((resolve, reject) => {
const arr = []
let sum = 0
promises.forEach((pro, index) => {
pro.then((res) => {
arr[index] = {
status: 'resolved',
value: res
}
}, (err) => {
arr[index] = {
status: 'rejected',
reason: err
}
}).finally(() => {
sum++
if (sum === promises.length) {
resolve(arr)
}
})
})
})
}
static race(promises) {
return new promise((resolve, reject) => {
promises.forEach((pro) => {
pro.then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
})
})
}
static any(promises) {
return new promise((resolve, reject) => {
let sum = 0
promises.forEach((pro) => {
pro.then((res) => {
resolve(res)
}).finally(() => {
sum++
if (sum === promises.length) {
reject(new Error('All promises were rejected'))
}
})
})
})
}
}
测试
js
// -------------------------- 整体测试
new promise((resolve, reject) => {
console.log(1);
resolve(2)
}).then(res => {
console.log('then', res);
return 3
}).then(res => {
console.log('then2', res);
throw new Error('finally') // 错误会传递
}).finally(() => {
console.log('结速了');
// 会保持上一个promise的结果 无论成功的还是失败的
// finally自己创建的promise以及return 都不会传递给下一位
// 除非创建错误
// throw new Error('finally') // 错误会传递
// new promise 和 return 都不能传递给下个then
// return 'finally'
// return new promise((resolve, reject) => {
// resolve('finally')
// })
}).then((res) => {
console.log(res + '还没有结束');
}).catch((e) => {
console.log(e + '还没有结束');
})
js
// -------------------------- 测试 any race
const pr1 = new promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 1000)
})
const pr2 = new promise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 200)
})
promise.race([pr1, pr2]).then((res) => {
console.log('成功', res);
}).catch((err) => {
console.log('失败', err);
})
promise.any([pr1, pr2]).then((res) => {
console.log('成功', res);
}).catch((err) => {
console.log('失败', err);
})
js
// -------------------------- 测试 all allSettled
const pr = [1, 2, 3, 4, 5].map((item) => {
return new promise((resolve, reject) => {
setTimeout(() => {
if (item === 3) {
reject(item)
} else {
resolve(item)
}
}, 5000 - item * 1000)
})
})
promise.allSettled(pr).then(res => {
console.log(res);
})
promise.all(pr).then(res => {
console.log(res);
}).catch((err) => {
console.log(err);
})
promise任务调度
js
class Scheduler {
constructor(max) {
this.max = max;
this.count = 0;
this.taskList = [];
}
// 这里用到了 await 的闭包特性,使得每次执行的 fun 都是正确的
async add(fun) {
if (this.count >= this.max) {
await new Promise(reslove => this.taskList.push(reslove))
}
this.count++
const res = await fun()
this.count--
this.taskList.length && this.taskList.shift()()
return res
}
}
// 延迟函数
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
// 同时进行的任务最多2个
const scheduler = new Scheduler(2);
// 添加异步任务 (模仿真实请求接口)
// time: 任务执行的时间
// val: 参数
const addTask = (time, val) => {
scheduler.add(() => {
return sleep(time).then(() => console.log(val));
});
};
addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// 2
// 3
// 1
// 4