记录下所学的,来检验自己的掌握程度
试着手动实现个promise
let promise1 = new Promise((resolve, reject)=>{
setTimeout(() => {
resolve('张三');
}, 2000);
})
promise1
.then(res=>{
console.log(res); // 两秒后打印出了 '张三'
},err=>{
console.log(err);
});
// 来实现这样的一个函数
/*
注意的点:
1 状态只能 pending -> resolved pending -> rejected
2 从上边可以看出 then 函数是在 原型上边
*/
function MyPromise(exeuctor){
self.status = 'pending';
self.value = '';
self.reason = '';
// 改变为成功的状态
function resolve(data){
self.value = data;
self.status = 'resolved';
}
// 改变为失败的状态
function reject(reason){
self.reason = reason;
self.status = 'rejected';
}
try {
exeuctor(resolve, reject)
} catch (err) {
// 执行异步函数出错 直接改变为失败状态
reject(err);
}
}
MyPromise.prototype.then = function(onresolve, onrejected){
if(this.status == 'resolved'){
onresolve(self.value);
}
if(this.status == 'rejected'){
onrejected(self.reason);
}
}
let myPromise1 = new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve('李四');
}, 2000);
})
myPromise1.then((data)=>{
console.log(data);
},err=>{
console.log(err);
})
李四 并没有被打印出来
分析原因得知 函数并没有 先执行 resolve('李四') 然后执行 onresolve 打印出 李四
先执行了 then中的函数 2s后执行 resolve('李四') 顺序反了
怎样才能 在执行 resolve('李四') 函数后,立即执行 then 注册的函数?
调用then的时候 MyPromise 处于 pending的状态 可以在这个时候 存储then注册的函数
状态改变的时候 再来执行
来实现
function MyPromise(exeuctor){
let self = this;
self.status = 'pending';
self.value = '';
self.reason = '';
+ self.resolveCallbacks = [];
+ self.rejectCallbacks = [];
// 改变为成功的状态
function resolve(data){
self.value = data;
self.status = 'resolved';
+ self.resolveCallbacks.forEach(func => func(data));
}
// 改变为失败的状态
function reject(reason){
self.reason = reason;
self.status = 'rejected';
+ self.rejectCallbacks.forEach(func => func(reason));
}
try {
exeuctor(resolve, reject)
} catch (err) {
// 执行异步函数出错 直接改变为失败状态
reject(err);
}
}
MyPromise.prototype.then = function(onresolve, onrejected){
if(this.status == 'resolved'){
onresolve(this.value);
}
if(this.status == 'rejected'){
onrejected(this.reason);
}
+ if(this.status == 'pending'){
+ this.resolveCallbacks.push(onresolve);
+ this.rejectCallbacks.push(onrejected);
+ }
}
这样就成功的两秒后打印出了李四
在 pendding的时候 注册函数 在状态改变的时候 有个好听的名字 叫订阅发布
接下来就是令人头疼的 链式调用的实现了
链式调用 比如:promise1.then().then();
在调用then的时候需要返回一个 promise
也就是说每一次调用then 都等于 创建了一个 promise对象
先来实现一个简单的链式调用
思路就是 then 函数返回一个 promise
想实现这样一个简单的链式调用
改造then函数
MyPromise.prototype.then = function(onresolve, onrejected){
let promise2;
promise2 = new MyPromise((resolve, reject)=>{
if(this.status == 'resolved'){
// 为什么要加setTimeout?
// 首先是promiseA+规范要求的
// 其次是大家写的代码,有的是同步,有的是异步
// 所以为了更加统一,就使用为setTimeout变为异步了,保持一致性
setTimeout(() => {
try {
let x = onresolve(self.value);
resolvePromise(promise2,x,resolve,reject);
} catch (error) {
reject(error)
}
}, 0);
}
if(this.status == 'rejected'){
setTimeout(() => {
try {
let x = onrejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (error) {
reject(error)
}
}, 0);
}
if(this.status == 'pending'){
this.resolveCallbacks.push(()=>{
// 当第一个promise状态改变的时候 执行then注册的函数
// 并改变当前的 promise 的状态 就实现了链式调用
setTimeout(()=>{
try{
let x = onresolve(self.value)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
});
this.rejectCallbacks.push(()=>{
setTimeout(()=>{
try{
let x = onrejected(self.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
});
}
});
return promise2;
}
来测试下
let myPromise1 = new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve('李四');
}, 2000);
})
myPromise1
.then((data)=>{
console.log(data+'1');
},err=>{
console.log(err);
})
.then((data)=>{
console.log(data+'2');
},err=>{
console.log(err);
})
.then((data)=>{
console.log(data+'3');
},err=>{
console.log(err);
})
// 依次打印出了 李四1 李四2 李四3
实现个复杂的链式调用 当 let x = onresolve(this.value); 中的x为一个promise时 这时候就需要一个函数 来确定 x 是不是 promise
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise'))
}
let called
if(x !== null && (typeof x === 'object' || typeof x === 'function')){
try{
let then = x.then
if(typeof then === 'function'){
then.call(x,(y)=>{ //
if(called) return
called = true
// promise2 resolve reject 三个参数一直都是不变的
// 迭代出最后一个promise
resolvePromise(promise2,y,resolve,reject)
},(err)=>{
if(called) return
called = true
reject(err)
})
}else{
resolve(x)
}
}catch(e){
if(called) return
called = true
reject(e)
}
}else{
// 当then 注册的函数返回是一个常量的时候 就决议 promise
// 最后一个promise
resolve(x)
}
}
对我来说,其中最难理解的还是,resolvePormise 对返回是promise的处理 如果返回的是promise 就注册then函数,并使用 resolvePormise 处理 这样就处理了整个链式调用
完整代码,顺便测试下
function MyPromise(exeuctor){
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
self.resolveCallbacks = [];
self.rejectCallbacks = [];
// 改变为成功的状态
function resolve(data){
if(self.status == 'pending'){
self.value = data;
self.status = 'resolved';
self.resolveCallbacks.forEach(func => func());
}
}
// 改变为失败的状态
function reject(reason){
if(self.status == 'pending'){
self.reason = reason;
self.status = 'rejected';
self.rejectCallbacks.forEach(func => func());
}
}
try {
exeuctor(resolve, reject)
} catch (err) {
// 执行异步函数出错 直接改变为失败状态
reject(err);
}
}
function resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('Chaining cycle'));
}
let called; // 防止状态改变多次
if(x!==null&&(typeof x === 'object' || typeof x === 'function')){
try {
let then = x.then;
if(typeof then === 'function'){ // x 为 promise
then.call(x,y => {
if(called) return;
called = true;
resolvePromise(promise2,y,resolve,reject);
},err=>{
if(called) return;
called = true;
reject(err)
})
} else {
resolve(x);
}
} catch (err) {
if(called) return;
called = true;
reject(err);
}
} else {
/*
如果x是一个常量 就决议当前的promise 调用then注册的函数
*/
resolve(x);
}
}
MyPromise.prototype.then = function(onresolve, onrejected){
let promise2;
let self = this;
onresolve = typeof onresolve === 'function'?onresolve:val=>val;
onrejected = typeof onrejected === 'function'?onrejected: err=>{throw err}
promise2 = new MyPromise((resolve, reject)=>{
if(self.status === 'resolved'){
setTimeout(() => {
try {
let x = onresolve(self.value);
resolvePromise(promise2,x,resolve,reject);
} catch (error) {
reject(error)
}
}, 0);
}
if(self.status === 'rejected'){
setTimeout(() => {
try {
let x = onrejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (error) {
reject(error)
}
}, 0);
}
if(self.status === 'pending'){
self.resolveCallbacks.push(()=>{
// 同13
setTimeout(()=>{
try{
let x = onresolve(self.value)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
})
self.rejectCallbacks.push(()=>{
// 同13
setTimeout(()=>{
try{
let x = onrejected(self.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
})
}
});
return promise2;
}
MyPromise.defer = MyPromise.deferred = function(){
let dfd = {};
dfd.promise = new MyPromise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
module.exports = MyPromise;
接下来我们要安装一个插件,npm install promises-aplus-test -g
写出来了一个符合 promiseA+规范的myPromise,很开心, 非常推荐阅读 小邵教你玩转promise源码 我的这个记录也是来源于这篇文章; 接着来实现两个函数 race 和 all 相信大家都知道这两个函数的作用,不说这两个函数
race的实现
MyPromise.prototype.race = function(promises){
return new MyPromise((resolve, reject)=>{
promises.forEach(item=>{
item.then(resolve,reject);
})
})
}
// 测试
let raceRes = MyPromise.race([
new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve(2000)
}, 2000)
}),
new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve(5000)
}, 5000)
})
])
.then(res=>{
console.log(res); // 2000
},err=>{
console.log(err);
})
all的实现
MyPromise.prototype.all = function(promises){
return new MyPromise((resolve, reject)=>{
let resArr = [];
let i = 0;
function processData(key,res){
resArr[key] = res;
if(++i === promises.length){
resolve(resArr)
}
}
promises.forEach((item,key)=>{
item.then(res=>{
processData(key,res);
},err=>reject(err))
})
})
};
allSettled 实现,和all很一样
无论成功或者失败都会返回一个数组,每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。
MyPromise.prototype.allSettled = function(promises){
return new MyPromise((resolve, reject)=>{
if(!promises.length){
resolve([])
}
let resArr = [];
let i = 0;
function processData(key,res){
resArr[key] = res;
if(++i === promises.length){
resolve(resArr)
}
}
promises.forEach((item,key)=>{
let obj = {};
item.then(res => {
obj = {
status: 'fulfilled',
value: res
}
processData(key,obj)
},reason => {
obj = {
status: 'rejected',
reason
}
processData(key,obj)
})
})
})
};
resolve和reject
// resolve
MyPromise.prototype.resolve = function(value){
return new MyPromise((resolve, reject) => resolve(value))
}
// reject
MyPromise.prototype.reject = function(err){
return new MyPromise((resolve, reject) => reject(err))
}
catch的实现
// catch 其实和then几乎一样的,只不过是then多了一个成功的回调,
// catch只有一个失败的回调,其余是一样的,
MyPromise.prototype.catch = function(callback){
return this.then(null,reason=>callback(reason))
}
finally的实现,先来看mdn对finally的描述
finally() 虽然与 .then(onFinally, onFinally) 类似,它们不同的是:
- 调用内联函数时,不需要多次声明该函数或为该函数创建一个变量保存它。
- 由于无法知道
promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。 - 与
Promise.resolve(2).then(() => {}, () => {})(resolved的结果为undefined)不同,Promise.resolve(2).finally(() => {})resolved的结果为2。 - 同样,
Promise.reject(3).then(() => {}, () => {})(fulfilled的结果为undefined),Promise.reject(3).finally(() => {})rejected 的结果为3。
/*
两次用的都是resolve
finally调用了注册的函数callback,由于finally未收到任何参数
所以调用callback也不应该传递任何参数
*/
MyPromise.prototype.finally = function(callback){
return this.then(
res => this.resolve(callback()).then(() => res),
reason => this.resolve(callback()).then(() => {throw reason}),
)
}
非常推荐阅读 小邵教你玩转promise源码
记录下所学,水平有限难免错误,欢迎指出 ~~