通过前面儿篇的学习,我们认识到,想优雅地进行异步操作,必须要熟识-个极其重要的质概念Promise。 它是取代传统回调,实现同步链式写法的解决方案;是理解Generator、async/awat的关键。但是,对于初学者来说,Promise 并不是很好理解,其中的概念纷杂,且抽象程度较高。与此同时,在中高级前端开发面试中,对于Promise 的考查也多种多样,近几年流行“让面试者实现一个Promise” 。那么,本篇就带大家实现一个简单的Promise。
function Cpromise(executor){
this.status = 'pending'
this.value = ''
this.reason = ''
const resolve = value => {
if(this.status === 'pending'){
this.value = value
this.status = 'fulfilled'
}
}
const reject = reason => {
if(this.status === 'pending'){
this.status = 'rejected'
this.reason = reason
}
}
executor(resolve,reject)
}
Cpromise.prototype.then = function(onFulfilled,onReject){
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data
onReject = typeof onReject === 'function' ? onReject : error => { throw error }
if(this.status === 'fulfilled'){
onFulfilled(this.value)
}
if(this.status === 'rejected'){
onReject(this.reason)
}
}
解析:这就是promise的构架,现在还没首先一部功能,promise接受一个函数参数,在函数参数里传人promise对象声明的resolve和reject函数,然后执行函数体。每次实例一个pormise对象,都会声明状态status,成功结果value,失败结果reason。在resolve中把状态变化fulfilled,在reject中把状态变为rejected。promise的then函数接受俩个函数参数,给俩个函数设置默认值,实现promise穿透功能。状态为fulfilled执行第一参数函数,状态为rejected执行第二参数函数。
function Cpromise(executor){
this.status = 'pending'
this.value = ''
this.reason = ''
this.onFulfilledFncArr = []
this.onRejectFncArr = []
const resolve = value => {
if(value instanceof Cpromise){
value.then(resolve,reject)
}
setTimeout(() => {
if(this.status === 'pending'){
this.value = value
this.status = 'fulfilled'
this.onFulfilledFncArr.forEach( fn => {
fn(value)
})
}
})
}
const reject = reason => {
setTimeout(() => {
if(this.status === 'pending'){
this.status = 'rejected'
this.reason = reason
this.onRejectFncArr.forEach( fn => {
fn(reason)
})
}
})
}
executor(resolve,reject)
}
Cpromise.prototype.then = function(onFulfilled,onReject){
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data
onReject = typeof onReject === 'function' ? onReject : error => { throw error }
if(this.status === 'fulfilled'){
onFulfilled(this.value)
}
if(this.status === 'rejected'){
onReject(this.reason)
}
if(this.status === 'pending'){
this.onFulfilledFncArr.push(onFulfilled)
this.onRejectFncArr.push(onReject)
}
}
解析:在relsolve和rejects中加入setTimeout模拟微任务,在resolve中识别参数为prmise,则直接调用then函数。声明onFulfilledFncArr和onRejectFncArr数组存储多个then在promise决议时该调用的函数,在resolve调用时执行onFulfilledFnc里所有函数,给每个函数传入value。reject调用时,时执行onRejectFncArr里所有函数,给每个函数传入reason。
例:多个then的调用
let p = new Cpromise((res,rej) =>{
setTimeout(() => {
res(5)
},500)
})
p.then(res => {
console.log(res + 1);
})
p.then(res => {
console.log(res + 2);
})
关于then的俩个函数参数返回值,如果返回简单数据类型,返回一个pormise实例promise2,在其reslove、reject中传入返回值。如果返回值是是promise类型,那就进行遍历,看看这个返回值promise的then的onFulfilled的传入值是不是promise,是就再进行遍历。将最后拿到的值,决议promise2
例:then返回promise
new Cpromise((res,rej) => {
console.log('start');
setTimeout(() =>{
res(5)
},1000)
}).then(val => {
return new Cpromise((res,rej) => {
setTimeout(() => {
res(val + 5)
},1000)
})
}).then(val => {
return new Cpromise((res,rej) => {
setTimeout(() => {
res(val + 5)
},1000)
})
}).then(res => {
console.log(res);
})
代码如下:
function Cpromise(executor){
this.status = 'pending'
this.value = ''
this.reason = ''
this.onFulfilledFncArr = []
this.onRejectFncArr = []
const resolve = value => {
if(value instanceof Cpromise){
value.then(resolve,reject)
}
setTimeout(() => {
if(this.status === 'pending'){
this.value = value
this.status = 'fulfilled'
this.onFulfilledFncArr.forEach( fn => {
fn(value)
})
}
})
}
const reject = reason => {
setTimeout(() => {
if(this.status === 'pending'){
this.status = 'rejected'
this.reason = reason
this.onRejectFncArr.forEach( fn => {
fn(reason)
})
}
})
}
executor(resolve,reject)
}
Cpromise.prototype.then = function(onFulfilled,onReject){
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data
onReject = typeof onReject === 'function' ? onReject : error => { throw error }
let promise2
if(this.status === 'fulfilled'){
return Promise2 = new Cpromise((res,rej) => {
setTimeout(() => {
try {
let result = onFulfilled(this.value)
resolvePromise(promise2, result, res, rej)
} catch (error) {
rej(error)
}
})
})
}
if(this.status === 'rejected'){
return Promise2 = new Cpromise((res,rej) => {
setTimeout(() => {
try {
let result = onReject(this.value)
resolvePromise(promise2, result, res, rej)
} catch (error) {
rej(error)
}
})
})
}
if(this.status === 'pending'){
return Promise2 = new Cpromise((res,rej) => {
this.onFulfilledFncArr.push(() => {
try {
let result = onFulfilled(this.value)
resolvePromise(promise2, result, res, rej)
} catch (error) {
rej(error)
}
})
this.onRejectFncArr.push(() => {
try {
let result = onReject(this.season)
resolvePromise(promise2, result, res, rej)
} catch (error) {
rej(error)
}
})
})
}
}
function resolvePromise(promise2, result, res, rej){
if(result === promise2){
rej(new TypeError('error due circular reference'))
}
let consumed = false
let thenFn
if(result instanceof Cpromise){
if(result.status === 'pending'){
result.then((data) => {
resolvePromise(promise2, data, res, rej)
},rej)
}else{
result.then(res,rej)
}
return
}
const isComplexResult = target => (typeof target === 'function' || typeof target === 'Object') && (typeof target !== 'null')
if(isComplexResult(result)){
try {
thenFn = result.then
if(typeof thenFn === 'function'){
thenFn.call(result,
function(data){
if(consumed){
return
}
consumed = true
return resolvePromise(promise2, data, res, rej)
},function(error){
if(consumed){
return
}
consumed = true
return rej(error)
})
}else{
res(result)
}
} catch (error) {
if(consumed){
return
}
consumed = true
return rej(error)
}
}else{
res(result)
}
}
解析:在then中返回值为promise2,在promise2中对onFulfilled、onRejected的返回值进行resolvePromise函数遍历。resolvePromise函数工具流程:检测是不是promise类型,是,检测状态是不是pending,是then传入onFulfilled函数,函数体中继续resolvePromise。不是pending,直接then,传入promise2的resolve和reject。然后return。
不是promise类型,判断其是不是复杂数据类型,是,判断有没有then,有再判断是不是函数,是则传入俩个函数,在第一个函数中继续resolvePromise遍历。没有then,then不是函数,直接执行promise2的resolve。
Cpromise.prototype.catch = function(catchFn){
return new this.then(null,catchFn)
}
Cpromise.resolve = function(value){
new Cpromise(res => {
res(value)
})
}
Cpromise.reject = function(reason){
new Cpromise((res,rej) => {
rej(reason)
})
}
Cpromise.all = function(promiseArr){
return new Cpromise((allRes,allRej) => {
try {
const valArr = []
let onfulfilledPromiseCount = 0
for(let i=0; i {
valArr.push(res)
onfulfilledPromiseCount++
if(onfulfilledPromiseCount === promiseArr.length){
allRes(valArr)
}
},allRej)
}
} catch (error) {
allRej(error)
}
})
}
Cpromise.race = function(promiseArr){
return new Cpromise((raceRes,raceRej) => {
try {
for(let i=0; i
通过本篇的学习,相信读者对Promise这个概念的理解会大大加深。其实,实现一个Promise不是目的,并且实现这个Promnise也没有完全100%遵循规范,应该掌握概念,融会贯通。另外,从整体来看,这部分内容不好理解,如果暂时难以接受全部概念,也不要灰心。实现的代码就在那里,要有决心慢慢地掌握它。