结合MDN文档及b站学习视频掌握Promise的原理和实现
先明白以下几个问题:
Promise是什么?
Promise是javascript的一个内置对象,语法上是一个构造函数。
Promise的作用
(1)使回调函数更加灵活,不需提前指定回调函数。
(2)支持链式调用,封装异步操作,解决回调地狱。
回调地狱的缺点:
(1)代码不便阅读和维护
(2)需要逐层处理异常,没有异常传透功能
Promise的特点:
(1)有三种状态
pending: 初始状态,既不是成功,也不是失败状态。
resolved(fulfilled): 意味着操作成功完成。
rejected: 意味着操作失败。
只有内部执行函数的执行结果能决定状态的变化。
(2)一旦状态改变就不可再变。
使用方法举例:
//初始状态为pending
var pro = new Promise(resolve,reject)=>{
resolve(value);//若执行成功函数,则状态变为resolved
reject(reason);//若执行失败函数,则状态变为rejected
});
pro.then(fn1,fn2);//fn1:成功时的执行函数,fn2:失败时的执行函数
例:用Promis封装ajax
var ajax = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readystate == 4 && xhr.status == 200) {
resolve(xhr.responseText)
} else if (xhr.readystate == 4 && xhr.status !== 200) {
reject(xhr.statusText)
}
}
})
}
ajax.then(console.log(xhr.responseText)); //打印出返回的数据
下面开始逐步实现Promise
1.构造函数主体:传入参数为一个执行器函数executor,executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor。
function Promise(excutor) {
const self = this;
self.status = pending; //记录Promise状态
self.data = undefined; //保存成功或失败时参数
self.callbacks = []; //保存回调函数
try {
excutor(resolve, reject);
} catch (error) {
reject(error);
} //捕获异常处理,若发现抛出异常,直接执行失败函数
function resolve(value) { //成功函数,状态由pending->resolved,并执行成功时函数
if (self.status !== pending) {
return
}//若状态不为pending,则不能再改,直接返回
self.status = resolved;
self.data = value;
if (self.callbacks.length > 0) {
setTimeout(() => { //模拟异步,非源码实现原理
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
});
})
}
}
function reject(reason) {//失败函数,状态由pending->rejected,并执行失败时函数
if (self.status !== pending) {
return
}//若状态不为pending,则不能再改,直接返回
self.status = rejected;
self.data = reason;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(value)
});
})
}
}
}
2.Promise原型上的then方法(核心)
Promise.prototype.then = function(onResolved, onRejected) {
const self = this;
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; //异常传透核心
return new Promise((resolve, reject) => {
//执行成功或失败时的回调函数并根据结果返回新的Promise对象
function handle(callback) {
try {
const result = callback(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
//若状态还未改变,先将回调函数保存起来
if (self.status === pending) {
self.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (self.status === resolved) {
setTimeout(() => {
handle(onResolved);
})
} else {
setTimeout(() => {
handle(onRejected);
})
}
})
}
3.Promise原型上的catch方法
Promise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected)
} //执行失败时函数
4.Promise.resolved()和Promise.rejected()
Promise.resolved = function(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
} //直接将Promise状态变为resolved
Promise.rejected = function(value) {
return new promised((resolve, reject) => {
reject(reason)
})
} //直接将Promise状态变为rejected
5.Promise.all()
这个方法返回一个新的promise对象,该promise对象在参数对象promises里所有的promise对象都成功的时候才会触发成功,一旦有任何一个promises里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含promises里所有promise返回值的数组作为成功回调的返回值,顺序跟promises的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。
//chuang
Promise.all = function(promises) {
const values = new Array(promises.length)
let resolveCount = 0
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
resolveCount++;
values[index] = value
if (resolveCount === promises.length) {
resolve(values)
}
},
reson => {
reject(reason)
}
)
})
})
}
6.Promise.race()
谁先出结果就由谁决定;
当promises参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
})
})
}
完整版代码:
function Promise(excutor) {
const self = this;
self.status = pending;
self.data = undefined;
self.callbacks = [];
try {
excutor(resolve, reject);
} catch (error) {
reject(error);
}
function resolve(value) {
if (self.status !== pending) {
return
}
self.status = resolved;
self.data = value;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
});
})
}
}
function reject(reason) {
if (self.status !== pending) {
return
}
self.status = rejected;
self.data = reason;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(value)
});
})
}
}
}
Promise.prototype.then = function(onResolved, onRejected) {
const self = this;
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
return new Promise((resolve, reject) => {
function handle(callback) {
try {
const result = callback(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
if (self.status === pending) {
self.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (self.status === resolved) {
setTimeout(() => {
handle(onResolved);
})
} else {
setTimeout(() => {
handle(onRejected);
})
}
})
}
Promise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected)
}
Promise.resolved = function(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
Promise.rejected = function(value) {
return new promised((resolve, reject) => {
reject(reason)
})
}
Promise.all = function(promises) {
const values = new Array(promises.length)
let resolveCount = 0
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
resolveCount++;
values[index] = value
if (resolveCount === promises.length) {
resolve(values)
}
},
reson => {
reject(reason)
}
)
})
})
}
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
})
})
}
注:更多细节请自行学习相关视频和文档
参考文档:MDN文档中的Promise
参考学习视频:尚硅谷Promoise教程