前言:来来回回Promise已经学习了很多遍,一直没有成体系的总结过,这次就对promise做个了结,让我们一步步来实现一个Promise库。
首先第一点,我们需要了解Promise的本质:
Promise本质是一个会将传递进入的executor函数立刻执行的用来解决异步问题的类!
Promise基础版
ps:基础版和实际Promise库稍有区别,将在后续讲解完善。(then实质上是微任务)
然后,对比PromiseA+规范我们再来看下Promise的一些特性:
1.promise实例会有一个默认的pending状态,当调用resolve函数时,在函数内将pending状态修改为resolved状态,而调用reject函数时,在函数内部将pending状态修改为rejected状态;
2.一旦已经调用过resolve函数或者reject函数之后,再次调用则状态不会改变,也就是状态改变之后时不可逆的。
3.promise可以调用类的原型上的then方法,then方法接收两个函数,实例状态为resolved时,执行第一个函数,参数为resolve函数的传入值,实例状态为rejected时,执行第二个函数参数,参数为reject函数的传入值。
由此,我们可以得出Promise类基本结构:
function Promise (executor){
// 在promise内部定义一个状态 当前promise的状态
let self = this;
self.value = undefined;
self.reason = undefined;
self.status = 'pending'; // 默认promise的状态是pengding
function resolve(value){
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved'; // 成功态
}
}
function reject(reason){
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected'; // 失败态
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = Promise;
使用结果如下:
let Promise = require('./promise');
let p = new Promise(function(resolve,reject){
console.log('start');
reject('情人到了');
resolve('情人节到了');
});
// es6的内容
p.then((value)=>{
console.log('success',value);
},(reason)=>{
console.log('error',reason);
})
console.log('end');
//start
//error 情人到了
//end
Promise进阶版
在原有基础上,我们需要满足:
1.new Promise中可以包含异步逻辑
2.同一个实例可以多次then
所以我们需要对之前的基础版进行完善:
function Promise (executor){
// 在promise内部定义一个状态 当前promise的状态
let self = this;
self.value = undefined;
self.reason = undefined
self.status = 'pending'; // 默认promise的状态是pengding
self.onResolevedCallbacks = []; // 存放所有成功的回调
self.onRejectedCallbacks = []; // 存放所有失败的回调
function resolve(value){
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved'; // 成功态
self.onResolevedCallbacks.forEach(fn=>fn());
}
}
function reject(reason){
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected'; // 失败态
// 发布
self.onRejectedCallbacks.forEach(fn =>fn());
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
if(self.status === 'pending'){
// 订阅
self.onResolevedCallbacks.push(function(){
onFulfilled(self.value);
});
self.onRejectedCallbacks.push(function(){
onRejected(self.reason);
});
}
}
module.exports = Promise;
使用结果如下:
let Promise = require('./promise');
let p = new Promise(function(resolve,reject){
setTimeout(function(){
if(Math.random()>.5){
resolve("成功");
}else{
reject("失败");
}
},1000)
});
p.then((value)=>{
console.log('success',value);
},(reason)=>{
console.log('error',reason);
})
p.then((value)=>{
console.log('success',value);
},(reason)=>{
console.log('error',reason);
})
console.log('end');
//end
//success 成功
//success 成功
Promise高阶版
promise实例是支持链式调用的
在了解promise链式调用之前,我们先来看一下,未使用Promise的,通过回调函数方式实现的异步解决方案:
let fs = require('fs');
fs.readFile('./name.txt','utf8',function(err,data){
fs.readFile(data,'utf8',function(err,data){
console.log(data);
})
});
很明显这样的嵌套很容易形成回调地狱,也很不简洁。
然后对比一下使用了Promise之后的链式调用:
function readFile(url){
return new Promise((resolve,reject)=>{
fs.readFile(url,'utf8',function(err,data){
if(err) reject(err);
resolve(data);
})
})
}
readFile('./name.txt').then((data)=>{
return readFile(data); // age.txt1
}).then(data=>{
return 100;
}).then(data=>{
console.log(data)
}).catch(err=>{
throw err
}).then((data)=>{
console.log(data);
},()=>{
console.log('error');
})
很明显,我们现在可以看出Promise的一个明显的优点: 就是【链式调用】
Promise链式调用的特点:
1) 如果一个then方法返回一个普通值, 这个值会传递给下一次then中作为成功的结果
2) 不是普通值 (promise 或者报错了),会根据返回的promise是成功还是失败决定下一个then是成功还是失败
3) 捕获错误机制(默认会找离自己最近的then的失败)找不到就向下找
4) promise调用then后 会返回一个新的promise
现在我们继续完善,来实现满足链式调用的Promise类
function Promise (executor){
let self = this;
self.value = undefined;
self.reason = undefined
self.status = 'pending';
self.onResolevedCallbacks = [];
self.onRejectedCallbacks = []; // 存放所有失败的回调
function resolve(value){
if(value instanceof Promise){
// if(value.then && typeof value.then === 'function'){
return value.then((data)=>{
resolve(data)
},y=>{
reject(y);
});
// }
}
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved'; // 成功态
self.onResolevedCallbacks.forEach(fn=>fn());
}
}
function reject(reason){
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected'; // 失败态
// 发布
self.onRejectedCallbacks.forEach(fn =>fn());
}
}
try{
executor(resolve,reject); // 用户会调用resolve / reject
}catch(e){
reject(e); // 说明失败了
}
}
function resolvePromise(promise2,x,resolve,reject){ // 判断x 是不是promise
if(promise2 === x){ // 表示防止自己等待自己
return reject(new TypeError('循环引用了'));
}
// 保证当前x 是一个引用类型
let called; // 表示当前有没有被调用过
if((x!==null && typeof x === 'object') || typeof x === 'function'){
// 很有可能是一个promise
try{
let then = x.then; // then属性具有getter 此时获取时会发生异常
if(typeof then === 'function'){ // 就认为promise
then.call(x,y=>{ // y有可能是一个promise
// 一直解析 直到结果是一个常量为止
if(called) return; // 给别人的promise增加的
called = true;
resolvePromise(promise2,y,resolve,reject);
//resolve(y); // 成功拿到成功的结果让promise2变成成功态
},r=>{
if(called) return;
called = true;
reject(r);
});
}else{ // 当前这个then是一个对象 普通对象
resolve(x); // {a:1}
}
}catch(e){ // 防治别人的库中既调用了成功又有失败
if(called) return;
called = true;
reject(e);
}
}else{
resolve(x);// 普通值 直接成功即可
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
onFulfilled = typeof onFulfilled === 'function'?onFulfilled : value=> value;
onRejected = typeof onRejected === 'function'? onRejected:function(err){
throw err;
}
let self = this;
// 调用then后需要再次 返回一个全新的promise
// 我需要拿到当前then方法 成功或失败执行后的结果
let promise2 = new Promise(function(resolve,reject){
if(self.status === 'resolved'){
setTimeout(()=>{ // 这里要使用promise2 所有 需要增异步保证可以获取到promise2
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e); // 如果执行函数时抛出失败 那么会走向下一个then的失败状态
}
},0)
}
if(self.status === 'rejected'){
setTimeout(()=>{
try{
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
console.log('err')
reject(e);
}
},0)
}
if(self.status === 'pending'){
// 订阅
self.onResolevedCallbacks.push(function(){
setTimeout(()=>{
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},0)
});
self.onRejectedCallbacks.push(function(){
setTimeout(()=>{
try{
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
});
return promise2;
}
module.exports = Promise;
Promise最终版
最后我们再补上promise一些其他函数的实现
// 让你实现一个promise的延迟对象 defer
Promise.defer =Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
Promise.prototype.catch = function(errFn){
return this.then(null,errFn)
}
Promise.all = function(values){ console.log('my-promise')
return new Promise((resolve,reject)=>{
let arr = []; // 最终结果的数组
let index = 0;
function processData(key,value){
index++;
arr[key] = value;
if(index === values.length){ // 如果最终的结果的个数和values的个数相等 抛出结果即可
resolve(arr);
}
}
for(let i = 0;i<values.length;i++){
let current = values[i];
if(current && current.then && typeof current.then == 'function'){
// promise
current.then(y=>{
processData(i,y);
},reject)
}else{
processData(i,current);
}
}
})
}
Promise.race = function(values){
return new Promise((resolve,reject)=>{
for(let i = 0;i<values.length;i++){
let current = values[i];
if(current && current.then && typeof current.then == 'function'){
// race方法 如果已经成功了 就不会失败了 反之一样
current.then(resolve,reject)
}else{
resolve(current);
}
}
});
}
Promise.resolve = function(arg){
if(arg && arg.then && typeof arg.then == 'function') {
if(arg instanceof Promise){
return arg;
}else{
return new Promise(arg.then).then();
}
}
return new Promise((resolve,reject)=>{
resolve(arg);
})
}
Promise.reject = function(arg){
return new Promise((resolve,reject)=>{
reject(arg);
})
}