一、Promise的执行原理:
Promise对象首先存在三种状态:pendding、fulfilled、rejected。在通过new Promise的时候,Promise内部默认的状态是pendding,Promise的状态一旦改变后就不会再进行改变。例如用原生的Promise举个例子:
{
let p = new Promise((resolve, reject) => {
resolve('OK');
reject('error');
}).then(res => {
console.log("resolve结果", res);
}).catch(err => {
console.log("reject结果", err);
})
}
Promise的状态改变只有两种类型:从pendding==>fulfilled或者pendding==>rejected。状态的修改途径:1.通过执行resolve函数把状态修改为fulfilled状态。2.通过reject函数把状态修改为rejected状态。3.在excutor函数中try到错误会把状态改为rejected。对第三种情况举个例子:
{
let p = new Promise((resolve, reject) => {
throw new Error("出错了")
})
console.log(p);
}
Promise的基本使用:
1.创建实例
let p = new Promise((resolve, reject) => {
})
2. .then回调 .then函数,可以接受两个回调函数参数,第一个回调处理resolve成功后的下一步操作,第二个处理rejected失败的下一步操作,同时.then函数会返回一个新的Promise对象,这里保证了可以进行链式调用,.then后可再次进行.then。
let p = new Promise((resolve, reject) => {
resolve("OK");
});
p.then(res => {
console.log(res);
return '第二次OK'
}).then(res => {
console.log(res);
})
3. .catch .catch方法进行处理通过reject()执行后的下一步操作,对错误进行处理。
let p = new Promise((resolve, reject) => {
reject("Error")
});
p.catch(err => {
console.log(err);
})
了解了Promise的基本使用,现在一步一步的去实现MyPromise
二、手写Promsie
借鉴的文章:https://mengera88.github.io/2017/05/18/Promise原理解析/ 第一步初始化:首先是通过new创建的,且接收一个excutor函数,接收2个参数:resolve、reject,resolve是Promise内部的函数用于把状态改为fulfilled,reject是Promise内部的函数用于把状态改为rejected,并且Promise的初始状态是pendding,所以列出如下结构:
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
function resolve(data) {
}
function reject(data) {
}
executor(resolve, reject);
}
测试一下:
let p = new MyPromise((resolve, reject) => {});
console.log(p);
输出结果: 第二步修改MyPromise的状态:在excutor中调用resolve或者reject函数进行改变MyPromise的状态,修改promiseStatus的值。 结构如下:
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
const self = this;
function resolve(data) {
self.promiseStatus = 'fulfilled';
}
function reject(error) {
self.promiseStatus = 'rejected';
}
executor(resolve, reject);
}
测试一下:
let p = new MyPromise((resolve, reject) => {
resolve('OK');
reject('error');
});
console.log(p);
输出结果: 输出结果没错,也没报错,但是不符合Promise的逻辑,因为状态一旦改变就不再会改变状态。意思是resolve()或者reject()只能执行其中一个,这里就错了,先执行了resolve('OK'),然后执行了reject(''error),所以该状态变为了rejected。 修改后的代码:
```javascript
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
const self = this;
executor(resolve, reject);
function resolve(data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'fulfilled';
}
}
function reject(data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'rejected';
}
}
}
第三步处理resolve()、reject()的参数: 把参数进行保存到Promise的promiseValue中,便于在.then和.catch的回调函数中访问。 修改后的代码:
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
const self = this;
function resolve(data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'fulfilled';
self.promiseValue = data;
}
}
function reject(data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'rejected';
self.promiseValue = data;
}
}
executor(resolve, reject);
}
测试一下:
let p = new MyPromise((resolve, reject) => {
resolve('OK');
reject('error');
});
console.log(p);
测试结果:
执行了resolve('OK')之后就没有执行reject(‘error’),保证了修改了状态之后不能再改,同时resolve('OK')中的参数保存到了promiseValue。
第四步完成.then函数链式调用,.then()接收2个参数,第一个回调是处理resolve函数,第二个处理reject函数,而且.then会返回一个新的Promise,新的Promise的Value是回调返回的值,一个老的Promise和新的Promise怎么连接上呢。
这里最重要的部分来了:用一个bridge函数,该函数接收一个对象参数,该对象保存了老的Promise的回调onResolve和新的Promise的resolve函数,通过老的Promise的onResolve执行后会得到一个返回值,该返回值是给下一个新Promise的,然后再调用新Promise的resolve方法就可以把值进行传递了。
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
const self = this;
executor(resolve, reject);
function resolve(data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'fulfilled';
self.promiseValue = data;
}
}
function reject(data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'rejected';
self.promiseValue = data;
}
}
function bridge (callBack) {
if (!callBack.onResolve) {
callBack.resolve(self.promiseValue);
return;
}
let data = callBack.onResolve(self.promiseValue);
callBack.resolve(data);
}
MyPromise.prototype.then = function(onResolve) {
return new MyPromise(resolve => {
bridge({onResolve: onResolve || null, resolve });
})
}
}
测试一下:
let p = new MyPromise((resolve) => {
resolve('OK');
}).then(res => {
console.log(res);
})
第五步:错误处理(reject)。 1.当在excutor函数中抛出了错误,得直接修改MyPromise的状态为rejected。 2.或者通过reject(err)执行把状态改为rejected。 进入.catch()函数的前提:reject()执行后,且.then()函数中没有第二个参数处理失败结果。 加上.catch方法后的代码:
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
const self = this;
try{
executor(resolve, reject);
} catch(err) {
reject(err);
}
function resolve (data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'fulfilled';
self.promiseValue = data;
}
}
function reject (data) {
if (self.promiseStatus === 'pendding') {
self.promiseStatus = 'rejected';
self.promiseValue = data;
}
}
function bridge(callBack) {
if (self.promiseStatus === 'fulfilled') {
if (!callBack.onResolve) {
callBack.resolve(self.promiseValue);
return
}
let data = callBack.onResolve(self.promiseValue);
callBack.resolve(data);
}
if (self.promiseStatus === 'rejected') {
if (!callBack.onReject) {
callBack.reject(self.promiseValue);
return;
}
let error = callBack.onReject(self.promiseValue);
callBack.resolve(error);
}
}
this.then = function (onResolve, onReject) {
return new MyPromise((resolve, reject) => {
bridge({
onResolve: onResolve || null,
onReject: onReject || null,
reject,
resolve
})
})
}
this.catch = function (onReject) {
return new MyPromise(resolve => {
bridge({
onReject: onReject || null,
resolve
})
})
}
}
测试一下:
let p = new MyPromise((resolve, reject) => {
reject("error")
}).catch(err => {
console.log(err);
})
let p = new MyPromise((resolve, reject) => {
reject("error")
}).then(() => {}, err => {
console.log(err);
})
上面的输出好像看似没问题,.then .catch的测试都没有什么问题,以上的测试都是在测试同步代码,然而Promise的用途就是处理异步操作。 第六步:这时候来试一下在excutor中加入定时器(setTimeout)来模拟异步操作。 加了定时器测试代码如下:
测试代码:
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("OK");
}, 1000)
}).then( res => {
console.log(res);
})
这时候会想:1s后执行了resolve(‘OK’),为什么没输出’OK‘呢。
再改一下测试代码,把.then的执行延迟2000ms执行看看:
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("OK");
}, 1000)
})
setTimeout(() => {
p.then( res => {
console.log(res);
})
}, 2000)
原因:当正常书写了.then后,那么这时候会立即执行.then函数,然而这时候的resolve(’OK‘)还没开始执行,得1s后再执行,所以这时候的状态还是pendding,再看看.then函数和bridge函数的逻辑,不满足条件就不会输出什么,只有在resolve(‘OK’)执行后再调用bridge就会正确的执行。
怎么解决呢?
解决办法:通过回调函数处理。进入bridge函数后判断状态,pendding状态就先把回调函数保存起来,在resolve()函数执行的时候再去循环调用这些回调函数。 修改后的代码:
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
let callBackList = []
const self = this;
try {
executor(resolve, reject);
} catch(e) {
reject(e);
}
function resolve (data) {
if (self.promiseStatus === 'pendding') {
self.promiseValue = data;
self.promiseStatus = 'fulfilled';
callBackList.forEach(objFun => {
bridge(objFun);
})
}
}
function reject (error) {
if (self.promiseStatus === 'pendding') {
self.promiseValue = error;
self.promiseStatus = 'rejected';
callBackList.forEach(objFun => {
bridge(objFun);
})
}
}
function bridge (callBack) {
if (self.promiseStatus === 'pendding') {
callBackList.push(callBack);
return;
}
if (self.promiseStatus === 'fulfilled') {
if (!callBack.onResolve) {
callBack.resolve(self.promiseValue);
return
}
let data = callBack.onResolve(self.promiseValue);
callBack.resolve(data);
}
if (self.promiseStatus === 'rejected') {
if (!callBack.onReject) {
callBack.reject(self.promiseValue);
return;
}
let error = callBack.onReject(self.promiseValue);
callBack.resolve(error);
}
}
this.then = function (onResolve, onReject) {
return new MyPromise((resolve, reject) => {
bridge({
onResolve: onResolve || null,
onReject: onReject || null,
reject,
resolve
})
})
}
this.catch = function (onReject) {
return new MyPromise(resolve => {
bridge({
onReject: onReject || null,
resolve
})
})
}
}
测试代码:
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("OK");
}, 1000)
}).then(res => {
console.log(res);
})
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject("error");
}, 1000)
}).then(() => {}, err => {
console.log(err);
})
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('OK')
}, 1000)
}).then(res => {
console.log(res);
return '55555555'
}).then(res => {
console.log(res);
})
封装的全部代码:
function MyPromise(executor) {
this.promiseStatus = 'pendding';
this.promiseValue = null;
let callBackList = []
const self = this;
try {
executor(resolve, reject);
} catch(e) {
reject(e);
}
function resolve (data) {
if (self.promiseStatus === 'pendding') {
self.promiseValue = data;
self.promiseStatus = 'fulfilled';
callBackList.forEach(objFun => {
bridge(objFun);
})
}
}
function reject (error) {
if (self.promiseStatus === 'pendding') {
self.promiseValue = error;
self.promiseStatus = 'rejected';
callBackList.forEach(objFun => {
bridge(objFun);
})
}
}
function bridge (callBack) {
if (self.promiseStatus === 'pendding') {
callBackList.push(callBack);
return;
}
if (self.promiseStatus === 'fulfilled') {
if (!callBack.onResolve) {
callBack.resolve(self.promiseValue);
return
}
let data = callBack.onResolve(self.promiseValue);
callBack.resolve(data);
}
if (self.promiseStatus === 'rejected') {
if (!callBack.onReject) {
callBack.reject(self.promiseValue);
return;
}
let error = callBack.onReject(self.promiseValue);
callBack.resolve(error);
}
}
this.then = function (onResolve, onReject) {
return new MyPromise((resolve, reject) => {
bridge({
onResolve: onResolve || null,
onReject: onReject || null,
reject,
resolve
})
})
}
this.catch = function (onReject) {
return new MyPromise(resolve => {
bridge({
onReject: onReject || null,
resolve
})
})
}
}
|