Promise作用
所谓Promise,中文意思是期限,承诺的意思,就是使用一个对象来传递一个未来将要发生的事(promise),而到了那时(then),再来查看成功还是失败再来绝对将要执行的操作。(onResolve,onReject)。
博主一年前曾粗略地学习过promise地使用与实现,但当时理解较为浅薄。冷饭重炒,希望能发现一些新的东西。希望读者能够加以批评指正。
博主这次希望以一个循序渐进的过程(前提是熟悉promise的使用)来搭建这次代码实现;若只需代码,则直接移步第五章。
1. 框架搭建
(1) Promise状态值PromiseState(初始为pengding,可利用Promise中的resolve与reject来修改该值);Promise中的返回结果值PromiseResult;
(2) 传入构造函数中的执行器函数excutor;
(3) resolve()函数与reject()函数;
(4) 因需要创建函数resolve()与reject(),其中的this指向会改变,需要保留外层的this;
(5) 创建原型上的then()方法供Promise实例进行调用。
因此有如下代码:
function MyPromise(excutor) {
let self = this // 保留外层this
self.PromiseState = 'pending' // 指定初始创建时的状态值
self.PromiseResult = null // 初始化返回值
function resolve(data) { // 定义resolve与reject
}
function reject(data) {
}
excutor(resolve,reject) // 执行执行器函数
}
MyPromise.prototype.then = function(onResolved,onRejected) {
// then()中一般情况下会传入两个回调
}
2. resolve()与reject()的初步实现
(1) resolve()与reject()的作用是修改实例对象中的状态值(PromiseState)与返回值(PromiseResult);
(2) resolve()的作用是修改状态为'fulfilled'或'resolved',这里以’fulfilled‘为准,修改结果值为传入的参数值;
(3) reject()的作用是修改状态为'rejected',修改结果值为传入的参数值;
(4) 需要注意的是,在Promise传入的执行器函数中,状态值只能修改一次。
(5) resolve()中的参数值若为非Promise实例对象,则按原样执行,若为Promise实例对象,则执行then()方法并返回。
因此代码变为:
function MyPromise(excutor) {
let self = this // 保留外层this
self.PromiseState = 'pending' // 指定初始创建时的状态值
self.PromiseResult = null // 初始化返回值
function resolve(data) { // 定义resolve与reject
if(data instanceof MyPromise) { // 若为MyPromise实例,则执行then()再返回
return data.then(resolve,reject)
}
if(self.PromiseState !== 'pending') return; //若不为pending则直接返回,防止多次修改
self.PromiseState = 'fulfilled' // 修改状态值
self.PromiseResult = data // 修改结果值
}
function reject(data) {
if(self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
}
excutor(resolve,reject) // 执行执行器函数
}
MyPromise.prototype.then = function(onResolved,onRejected) {
// then()中一般情况下会传入两个回调
}
3. 异常throw处理
原生的Promise中包含throw(抛出错误的异常处理),效果等同于reject()使用try {} catch(e) {}
function MyPromise(excutor) {
let self = this // 保留外层this
self.PromiseState = 'pending' // 指定初始创建时的状态值
self.PromiseResult = null // 初始化返回值
function resolve(data) { // 定义resolve与reject
if(data instanceof MyPromise) { // 若为MyPromise实例,则执行then()再返回
return data.then(resolve,reject)
}
if(self.PromiseState !== 'pending') return; //若不为pending则直接返回,防止多次修改
self.PromiseState = 'fulfilled' // 修改状态值
self.PromiseResult = data // 修改结果值
}
function reject(data) {
if(self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
}
try {
excutor(resolve,reject) // 执行执行器函数
} catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onResolved,onRejected) {
// then()中一般情况下会传入两个回调
}
4. then()方法的实现(resolve()与reject()的完善)
(1) then()方法存在一个返回值为Promise的实例对象;
(2) then()方法存在两个回调,第一个为成功之后执行的操作,第二个为失败之后执行的操;
(3) then()方法两个回调中都含有参数,其实这个值是创建Promise实例执行完后的结果也就是PromiseResult值。
(4) 若在new 方法中存在延时调用,then()方法会先于延时执行完执行,但then()方法中的回调会后于延时执行完,PromiseResult
结果传递完成之后再执行。因此需要在构造函数中定义回调(此时回调可能不止一个,因此回调类型应该为数组),当状态为 'pending',(无延时时then()在执行执行器后执行,状态早就变了;因此状态为pending说明执行器中存在延时调用,这里可能有点绕,需要琢磨一下,反正需要明确的就是then()的执行时机)在执行then()时传入实例对象的回调数组属性中,并在执行resolve()和reject()修改状态后遍历实例对象上的回调数组属性并执行。
(5) then()方法存在延时调用,需要加上延时器。
(6) then中两个回调为可选值,可传可不传。
(7) then()中回调的返回值若为非Promise实例类型,则调用resolve(),若为Promise实例,则调用then来查看状态值与结果值通过resolve()与reject()来修改要返回的Promise实例的状态与结果。
于是代码变成:
function MyPromise(excutor) {
let self = this // 保留外层this
self.PromiseState = 'pending' // 指定初始创建时的状态值
self.PromiseResult = null // 初始化返回值
self.callbacks = [] // then()中的回调
setTimeout(() => { // 遍历callbacks,then()中回调延时执行
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
function resolve(data) { // 定义resolve与reject
if(data instanceof MyPromise) { // 若为MyPromise实例,则执行then()再返回
return data.then(resolve,reject)
}
if(self.PromiseState !== 'pending') return; //若不为pending则直接返回,防止多次修改
self.PromiseState = 'fulfilled' // 修改状态值
self.PromiseResult = data // 修改结果值
setTimeout(() => { // 遍历callbacks,then()中回调延时执行
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
function reject(data) {
if(self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
setTimeout(() => { // 遍历callbacks,then()中回调延时执行
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
try {
excutor(resolve,reject) // 执行执行器函数
} catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onResolved,onRejected) {
// then()中一般情况下会传入两个回调
let self = this // 保存外层this,防止返回MyPromise实例中this指向改变
if(typeof onResolved !== 'function') {
onResolved = value => value // 若未传成功回调,则执行默认回调
}
if(typeof onRejected !== 'function') {
onRejected = reason => {
throw reason // 若为传失败回调,则执行默认回调
}
}
return new MyPromise((resolve,reject) => { // 封装相同代码;检验回调返回值
function callback(type) {
try {
let result = type(self.PromiseResult)
if (result instanceof MyPromise) { // 若为MyPromise
result.then(v => {
resolve(v) // 通过回调的返回值执行then()后的状态与结果来修改返回的实例对象的返回值与结果
}, r => {
reject(r)
})
} else { // 若不为MyPromise实例,直接执行resolve来修改状态与返回值
resolve(result)
}
} catch (e) {
reject(e)
}
}
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
});
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected) // 延时调用
});
}
// 判断pending状态
if (this.PromiseState === 'pending') { // 执行器函数中存在回调,则将回调存入callbacks属性
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
5.完善Promise() (完善Promise函数的方法)
其实到这里还没有结束,因为Promise自己还有resolve()方法与reject()方法。这里与实例中的其实差不多,直接上代码:
```javascript
function MyPromise(excutor) {
let self = this // 保留外层this
self.PromiseState = 'pending' // 指定初始创建时的状态值
self.PromiseResult = null // 初始化返回值
self.callbacks = [] // then()中的回调
setTimeout(() => { // 遍历callbacks,then()中回调延时执行
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
function resolve(data) { // 定义resolve与reject
if(data instanceof MyPromise) { // 若为MyPromise实例,则执行then()再返回
return data.then(resolve,reject)
}
if(self.PromiseState !== 'pending') return; //若不为pending则直接返回,防止多次修改
self.PromiseState = 'fulfilled' // 修改状态值
self.PromiseResult = data // 修改结果值
setTimeout(() => { // 遍历callbacks,then()中回调延时执行
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
function reject(data) {
if(self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
setTimeout(() => { // 遍历callbacks,then()中回调延时执行
self.callbacks.forEach(item => {
item.onResolved(data)
})
});
}
try {
excutor(resolve,reject) // 执行执行器函数
} catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onResolved,onRejected) {
// then()中一般情况下会传入两个回调
let self = this // 保存外层this,防止返回MyPromise实例中this指向改变
if(typeof onResolved !== 'function') {
onResolved = value => value // 若未传成功回调,则执行默认回调
}
if(typeof onRejected !== 'function') {
onRejected = reason => {
throw reason // 若为传失败回调,则执行默认回调
}
}
return new MyPromise((resolve,reject) => { // 封装相同代码;检验回调返回值
function callback(type) {
try {
let result = type(self.PromiseResult)
if (result instanceof MyPromise) { // 若为MyPromise
result.then(v => {
resolve(v) // 通过回调的返回值执行then()后的状态与结果来修改返回的实例对象的返回值与结果
}, r => {
reject(r)
})
} else { // 若不为MyPromise实例,直接执行resolve来修改状态与返回值
resolve(result)
}
} catch (e) {
reject(e)
}
}
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
});
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected) // 延时调用
});
}
// 判断pending状态
if (this.PromiseState === 'pending') { // 执行器函数中存在回调,则将回调存入callbacks属性
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
resolve(value)
}
})
}
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
.catch()方法的完善
其实就是调用失败的回调,也就是调用then()方法第一个参数不传。只传第二个参数。
MyPromise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
.all()方法的完善
.all()方法的执行就是传入一个promise数组,若全为成功回调,则返回的状态值为成功,同时结果变为成功结果的数组,但传入的顺序不能变化。若存在失败,则返回第一个失败回调的状态与结果。
代码如下:
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
let count = 0
let arr = [] // 接收结果
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
arr[i] = promises[i] // 这里不能用push()推入数组的原因是若存在延时调用,执行完成顺序与传入顺序可能不同
count++
if (count === promises.length) {
resolve(arr)
}
}, r => {
reject(r)
})
}
})
}
.race()方法的完善
.race()方法就是传入一个promise数组,输出最先执行完成的promise对象的状态与结果
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
resolve(v)
}, r => {
reject(r)
})
}
})
}