学习了Promise的A+规范,以及手写一个Promise后,我对Promise学到的结果。
平常也有用到过promise来处理异步,先回顾下promise的用法
new Promise((resolve,reject) => {异步操作并改变状态}).then(onfullfilled, onrejected)
const myPromise = new Promise((resolve,reject) => {
//写一些异步操作,比如ajax请求
if(window.onError){
reject('页面加载失败');
}
setTimeout(() => {
resolve('异步返回结果');
}, 1000)
}).then((data) => {
console.log(data); // 异步返回结果
}).catch((reason)=>{
console.log(reason); // 页面加载失败
})
这个promise其实就是处理一件一段时间之后才能得到结果的事件,promise将将要执行的事件作为函数传入,并在得到结果时,resolve或者reject改变promise的状态并且改变结果,然后通过then或catch执行得到结果之后的事情。
一、每个promise都有三个状态
pending 初始化,可改变
fullfilled 成功,不可改变
rejected 失败,不可改变
promise的状态改变流程
二、resolve和reject函数
resolve:实参是定义在构造函数中的函数,
作用:
改变状态pending => fullfilled
改变结果 value = data
reject:实参是定义在构造函数中的函数,
作用:
改变状态pending => rejected,
改变结果 reason= reason
三、then:作为promise提供的一个方法, 用来访问最终的结果, 无论是value还是reason.
promise.then(onFulfilled, onRejected)
1.onFulfilled和onRejected,必须传入函数,如果不是函数,则改变为直接返回value或者reason的函数。
2.onFulfilled和onRejected只有当状态改变为相应的值后才可以执行,并将value和reason作为参数,且只可以执行一次
3.onFulfilled 和 onRejected 应该是微任务,这里用queueMicrotask来实现微任务的调用
4.then方法可以被调用多次
4.1promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调)
4.2promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)
5.then 应该返回一个promise
promise2 = promise1.then(onFulfilled, onRejected);
5.1 onFulfilled 或 onRejected 执行的结果为x, 调用 resolvePromise
5.2 如果 onFulfilled 或者 onRejected 执行时抛出异常e, promise2需要被reject
5.3 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled
5.4 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejected
不管是new Promise((resolve,reject)=> {})还是then((data) => {}),传入的函数都是在构造函数内执行的,所以实参是在构造函数内定义赋值的,所以我们再手写一个promise时,需要定义resolve和reject函数,以及得到的value,作为函数的实参
四、resolvePromise 就是处理then中onFulfilled 或 onRejected 返回的数据,并最终resolve或者reject掉promise2,改变promise2的状态,只有改变了状态,才能继续.then链式操作。
代码主要实现了A+规范里的内容:
如果 promise2 和 x 相等,那么 reject TypeError
如果 x 是一个 promsie
如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.
如果 x 被 fulfilled, fulfill promise with the same value.
如果 x 被 rejected, reject promise with the same reason.
如果 x 是一个 object 或者 是一个 function
let then = x.then.
如果 x.then 这步出错,那么 reject promise with e as the reason.
如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject);
rejectPromise 的 入参是 r, reject promise with r.
如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
如果调用then抛出异常e
如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
则,reject promise with e as the reason
五、手写一个promise
new MyPromise((resolve,reject) => {
}).then(() => {
}, () => {
})
new MyPromise((resolve,reject) => {
}).then(() => {
}).catch(() => {
})
从用法可以看出我们需要做的功能有
1.实现一个构造函数
2.构造函数接收一个函数作为参数
3.我们要再构造函数里面执行传进来的参数,并且传递实参resolve,reject, 作为提供给用户更改promise状态的方法
4.实现resolve,reject
5.实现then:
接收两个函数参数,分别在状态改变成对应值时触发
为了实现链式操作,继续让then返回一个promise
6.从promiseA+规范得知,我们还要实现一个resolvePromise去处理then返回的数据
1. promise是通过实例化的形式使用的,所以我们使用class写一个构造函数的方式实现。
class MyPromise {
construcor() {
}
}
2.promise始终是围绕三个状态状态实现异步的,所以我们定义下三个状态,并且给实例的promise状态、resolve结果值和reject原因赋初始值值。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
construcor() {
this.status = PENDING; // 初始状态为pending
this.value = null;
this.reason = null;
}
}
3.我们调用的resolve和reject方法去改变promise状态并且将他的参数赋值。
class MPromise {
constructor() {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
}
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
}
4.这个Promise类应该接收一个函数作为promise的入参,默认一进来就执行这个函数,并且把resolve和reject作为这个函数的入参抛出去,让使用的promise的人可以控制promise状态的改变。
class MPromise {
constructor(fn) {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
// 对用户自己传进来执行的代码块一般都做下try-catch
try {
// 这里绑定this是因为resolve执行的时候this的指向不一定是这个promise了,而我们要让他指向这里才能使用this.status...
fn(this.resolve.bind(this),this.reject.bind(this))
} catch(e) {
this.reject(e)
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
}
5.接下来实现一下请求状态改变后的方法,then()
a.接收两个函数参数,分别在状态改变成对应值时触发
为了实现链式操作,继续让then返回一个promise
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => {
return value;
};
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (value) => {
return value;
};
const promise2 = new MPromise((resolve, reject) => {
switch (this.status) {
case FULFILLED: {
realOnFulfilled(value);
}
case REJECTED: {
realOnRejected(value);
}
}