博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Promise源码解析-步步为营皆可及
阅读量:7067 次
发布时间:2019-06-28

本文共 25456 字,大约阅读时间需要 84 分钟。

本文根据promise的用法, 带您一步一步的了解promise的源码内幕; 本文采用要点、使用、源码分析的思路,步步为营,一点一点的剖析Promise的神秘世界; 本文Promise源码部分采用es5语法

Promise定义

  • promise是异步解决方案; 字面意思是"承诺",即未来某个时刻才能得到结果;
  • 从语法上来说,它是一个对象,从它可以获取异步操作的消息;

基本用法 - 构造函数

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例

  • 使用:
let p = new Promise();复制代码
  • 源码
function Promise(){ //... }复制代码
  • 解析: 构造函数与普通的函数并无二致, 只是我们在使用时需要通过new的方式来调用; 其中构造函数中的this指向new生成的对象实例;

Promise构造函数接收一个执行器函数(executor)作为参数, 该函数的两个参数分别为resolve和reject。当new生成对象实例的时候,Promise的参数executor会立即执行

  • 使用:
let p = new Promise((resolve, reject)=>{		// coding....	});复制代码
  • 源码:
function Promise(executor){				executor(resolve, reject);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	}复制代码
  • 解析: executor即调用时候传递进来的函数 (resolve, reject)=>{ // coding... }, 调用时会传递两个参数进去, 供// coding....处使用

执行器executor的参数(resolve, reject)是两个函数, 这两函数的作用:

  • resolve函数是将Promise对象的状态从"pending"变为"resolved"('未完成' => '成功'), 在异步操作成功时调用,并将异步操作结果作为参数传递出去(源码的resolve函数中接收);
  • reject函数 是将Promise对象的状态从"pending"变为"rejected"('未完成' => '失败'), 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去(源码的reject函数中接收);
  • 使用:
let p = new Promise((resolve, reject)=>{	    // coding....	    resolve('成功');	    // 或 reject('失败');	});	复制代码
  • 源码:
function Promise(executor){		    function resolve(value){	        console.log(value);   	// 调用resolve('成功'); 	=> 成功	    }	 	    function reject(reason){	        console.log(reason);		// 调用reject('失败');	=> 失败 	    }		    executor(resolve, reject);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	}复制代码
// 升级(添加状态)	function Promise(executor){		this.status = 'pending';		// 用于保存promise实例的状态,默认为pending,等待态		this.value 	= undefined;		// 保存成功时的值		this.reason = undefined;		// 保存失败时的原因	    function resolve(value){	        console.log(value);   	// 调用resolve('成功'); 	=> 成功			this.value = value;	    }	 	    function reject(reason){	        console.log(reason);		// 调用reject('失败');	=> 失败 			this.reason = reason;	    }		    executor(resolve, reject);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	}复制代码
// 升级(状态的转变) pending => fulfilled 或 pending => rejected	//一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果[摘自:http://es6.ruanyifeng.com/#docs/promise]	function Promise(executor){		let self 	= this;	    this.status = 'pending';  // pending => fulfilled | rejected	    this.value  = undefined;	    this.reason = undefined;	    // 成功 	    function resolve(value){	        if(self.status === 'pending'){	            self.value  = value;	            self.status = 'fulfilled';	            console.log(self.status)	        }  	    }		    function reject(reason){	        if(self.status === 'pending'){	            self.reason = reason;	            self.status = 'rejected';	            console.log(self.reason)	        }	    }			// 需要通过别名引用的方式; 因为resolve和reject中的this指向的是全局对象	    executor(resolve, reject);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	}复制代码
  • 解析:

    1. promise有三个状态: pending(进行中或等待中)、fulfilled(已成功)、rejeced(已失败)
    2. 使用时调用resolve函数,会把promise的状态转变为fulfilled,并且将成功的结果保存到promise实例的value属性
    3. 使用时调用reject函数,会把promise的状态转变为rejected,并且将失败的原因保存到promise实例的reason属性
    4. 状态的转变只能从pending => fulfilled 或 rejected, fulfilled和rejected之间是不能转换的;所以在resolve和rejected函数中添加了状态判断
    5. 调用resolve函数或reject函数会修改promise实例value(成功的结果)属性或reason(失败的原因),而此时在resolve和reject内部如何引用到promsie实例呢? -> 在Promise构造函数内部设置this的引用: let self = this; 在resolve或reject函数中,通过self引用promise实例;
  • 小结: 代码书写到此刻,我们打印Promise实例, 即可查看到当前实例的状态和相关属性;

let p = new Promise((resolve, reject)=>{    resolve('成功');	/*	  if (/* 异步操作成功 */){	    resolve(value);	  } else {	    reject(error);	  }	*/});console.log(p);  // Promise { status: 'fulfilled', value: '成功', reason: undefined }复制代码

如果Promise的执行器函数(executor)里面直接抛出异常呢? 捕获错误,相对于执行了reject

  • 使用:
let p = new Promise((resolve, reject)=>{	throw new Error('错误扔给你, 来打我呀^_^');});复制代码
  • 源码:
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){        // (value!=null && typeof value === 'object') || typeof value == 'function'        if(value instanceof Promise){            console.log('here');            // if(value.then && typeof value.then === 'function'){                return value.then((data)=>{                    console.log('11111111111')                    console.log(data)                    resolve(data)                },y=>{                    reject(y);                });            // }        }        console.log(self.status)        if(self.status === 'pending'){            self.value = value;            console.log('pending:',value)            self.status = 'resolved'; // 成功态            console.log('pending--', self.onResolevedCallbacks)            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); // 说明失败了    }}复制代码
  • 解析:

上面代码理解了,请移步下一个关 注意,为了行文方便,后面的resolved统一只指fulfilled状态,不包含rejected状态


Promise.prototype.then()

Promise.prototype.then()方法是Promise的核心方法; Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数;then方法的作用就是为promise实例添加状态改变时的回调函数;

  • 使用:
let p = new Promise((resolve, reject)=>{    resolve('成功');    // reject('失败');});p.then((value)=>{    // 成功时执行的回调    console.log('执行resolve,输出实例成功态的vlaue属性: ', value);}, (reason)=>{    // 失败时执行的回调    console.log('执行reject,输出实例失败态的reason属性: ', reason);});// => 执行resolve,输出实例成功态的vlaue属性:  成功复制代码
  • 源码:
function Promise(executor){		let self = this;    self.status = 'pending';  // pending => fulfilled | rejected    self.value  = undefined;    self.reason = undefined;    // 成功     function resolve(value){        if(self.status === 'pending'){            self.value  = value;            self.status = 'fulfilled';        }      }    function reject(reason){        if(self.status === 'pending'){            self.reason = reason;            self.status = 'rejected';        }    }	    try {        executor(resolve, reject);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject    }catch(err){        reject(err);    }}// Promise的核心方法Promise.prototype.then = function(onFulfilled, onRejected){    if(this.status === 'fulfilled'){        onFulfilled(this.value); // 这里传递成功的值    }    if(this.status === 'rejected'){        onRejected(this.reason);  // 这里传递失败的原因或错误    }};复制代码
  • 解析:
    1. then方法可以接收两个回调函数作为参数; 1> Promise实例对象的状态变为resolved时调用 2> Promsie实例的状态变为rejected时调用[可选];
    2. then的成功回调函数接收promise对象(也就是promise实例)的成功时的值作为参数(用于处理->执行);
    3. then的失败回调函数接收promise对象的失败时的原因或错误作为参数;

Promise.prototype.then() 与异步调用; 我们知道Promise主要是用来处理异步的, 当promise对象的状态在一段时间后发生变化时, 就会触发then方法绑定的回调函数; 这里要注意几点:

1> then方法在调用时会立即执行(同步), 关键在于then不同状态的回调函数只有在状态发生改变时执行(异步); 2> Promise是同步的, 实例新建后会立即执行; then是异步的,当状态改变时才执行复制代码
let promise = new Promise(function(resolve, reject) {	  console.log('Promise');	  resolve();	});		promise.then(function() {	  console.log('resolved.');	});		console.log('Hi!');	// => 依次输出: 'Promise'  'Hi!'  'resolved.'复制代码
  • 使用:
let p = new Promise((resolve, reject)=>{    setTimeout(()=>{        resolve('成功');			// 2秒钟之后,让promise的状态变成成功态    }, 2000);});p.then((value)=>{    // 成功时执行的回调    console.log('2秒后执行resolve,输出实例成功态的vlaue属性: ', value);}, (reason)=>{    // 失败时执行的回调    console.log('执行reject,输出实例失败态的reason属性: ', reason);});复制代码
  • 源码:
function Promise(executor){		let self = this;	    self.status = 'pending';  // pending => fulfilled | rejected	    self.value  = undefined;	    self.reason = undefined;		    self.onFulfilledCallbacks = [];     // 用于存放所有then方法成功态的回调	    self.onRejectedCallbacks = [];      // 用于存放所有then方法失败态的回调	    // 成功 	    function resolve(value){	        if(self.status === 'pending'){	            self.value  = value;	            self.status = 'fulfilled';	            self.onFulfilledCallbacks.forEach(fn=>fn()); // 当状态变为resolved时执行订阅的函数(then方法成功时的回调)	        }  	    }		    function reject(reason){	        if(self.status === 'pending'){	            self.reason = reason;	            self.status = 'rejected';	            self.onRejectedCallbacks.forEach(fn=>fn()); // 当状态变为rejected时执行订阅的函数(then方法失败时的回调)	        }	    }		    try {	        executor(resolve, reject);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	    }catch(err){	        reject(err);	    }	}			Promise.prototype.then = function(onFulfilled, onRejected){	    if(this.status === 'fulfilled'){	        onFulfilled(this.value); // 这里传递成功的值	    }		    if(this.status === 'rejected'){	        onRejected(this.reason);  // 这里传递失败的原因或错误	    }			// 在异步执行完成之前,promise的状态为pending,此时会把then两种状态的回调先存储起来,待状态改变后执行	    if(this.status === 'pending'){	        this.onFulfilledCallbacks.push(()=>{	            onFulfilled(this.value);	        });	        this.onRejectedCallbacks.push(()=>{	            onRejected(this.reason);	        });	    }	};复制代码
  • 解析:

    1. 回调的存储和调用是一个典型的发布/订阅模式;promise处于等待态时订阅,状态改变后执行发布;
    2. 在异步执行完成之前,此时promise的状态为pending,此时我们把then函数的参数(成功的回调resove和失败reject的回调)存储起来,待异步完成状态改变后调用;
    3. 用于存储then回调的是两个数组,一个是成功回调函数的数组,一个是失败回调函数的数组;
    4. 如果调用resolve函数和reject函数时带有参数, 那么它们的参数会被传递给then的回调函数; 如果没传具体的参数,那就将undefined传递过去;
    5. reject函数的参数通常是Error实例,表示抛出异常或错误;
    6. resolve函数的参数除了普通值以外, 还可以是另外一个Promise

then方法返回的是一个新的Promise实例(该实例不是原来那个Promise实例);

  • 使用(同步情况下的链式调用):
let p = new Promise((resolve, reject)=>{	    resolve(420);	});		p.then((value)=>{	    // 成功时执行的回调	    console.log('2秒后执行resolve,输出实例成功态的vlaue属性: ', value); // 2秒后执行resolve,输出实例成功态的vlaue属性:  420	    return value + 100;	}, (reason)=>{	    // 失败时执行的回调	    console.log('执行reject,输出实例失败态的reason属性: ', reason); 	}).then((value)=>{	    // then的成功回调里面输出,前一个then成功回调的返回值(即promise实例的value属性), 如果没有显示的return, 那么返回的是undefined	    console.log('第二个then的成功回调里面输出,前一个then成功回调的返回值: ',value); // 第二个then的成功回调里面输出,前一个then成功回调的返回值:  520	    return value + 200;	}).then((value)=>{	    console.log('第三个then的成功回调里面输出,前一个then成功回调的返回值: ',value);  // 第三个then的成功回调里面输出,前一个then成功回调的返回值:  720	});复制代码
  • 源码:
function Promise(executor){				let self = this;	    self.status = 'pending';  // pending => fulfilled | rejected	    self.value  = undefined;	    self.reason = undefined;		    self.onFulfilledCallbacks = [];     // 用于存放所有then方法成功态的回调	    self.onRejectedCallbacks = [];      // 用于存放所有then方法失败态的回调	    // 成功 	    function resolve(value){	        if(self.status === 'pending'){	            self.value  = value;	            self.status = 'fulfilled';	            self.onFulfilledCallbacks.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);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	    }catch(err){	        reject(err);	    }	}			Promise.prototype.then = function(onFulfilled, onRejected){	    let self = this;	    let promise2 = new Promise((resolve, reject)=>{	        console.log(this === self); // 这里因为使用了箭头函数,所以self === this, 指向同一个对象; 为了不混淆,后面将采用self的方式	        // 该executor函数会里面执行,因此把之前的状态判断及成功回调的代码移到此处与之前功能一样;	        // 需要说明的是这个promise需要根据上一个then的状态和值进行判断,故而设置self变量用于引用上一个this	        if(this.status === 'fulfilled'){	            let x = onFulfilled(this.value); // 成功回调; 这里的value指的是第一个Promise实例的value属性	            resolve(x);   // 将处理后的结果作为参数传递给promise实例的value属性; 同时也会传递给下一个then的成功回调	        }	    	        if(this.status === 'rejected'){	            try{	                let x = onRejected(this.reason);  // onRejected处理 	                reject(x);	            }catch(e){	                reject(e);	            }		        }	    	        if(this.status === 'pending'){	            this.onFulfilledCallbacks.push(()=>{	                onFulfilled(this.value);	            });	            this.onRejectedCallbacks.push(()=>{	                onRejected(this.reason);	            });	        }	    });			    return promise2;	};复制代码
  • 解析:

    1. then链式调用的关键是:then方法调用后返回一个新的Promise实例;
    2. 生成promise2实例时传递到Promise构造函数中的执行器excutor, 它里面用于判断状态的是上一个promise实例的状态,操作的都是上一个promise实例的属性;
    3. 有多少个then,就至少有多少个promise实例;
    4. 不论有多少个promise实例,在new新的Promise实例时都是判断前一个promise实例的状态、操作前一个promise实例的属性, 把前面的promise实例上的属性更新后, 传递到后面的then回调函数里面;
    5. 无论多少个then,都是前一个回调函数完成以后,将返回结果作为参数,传入下一个then的对应的回调中;
    6. 无论多少个then,某一状态的回调都是刚在一个数组,然后挨个的执行; 前一个执行完成后把实例属性传递给下一个回调函数

Promise.prototype.then() 与异步调用

  • 使用(异步情况下的链式调用):
let p = new Promise((resolve, reject)=>{    setTimeout(()=>{        resolve(420);    }, 3000);});p.then((value)=>{    // 成功时执行的回调    console.log('2秒后执行resolve,输出实例成功态的vlaue属性: ', value); // 2秒后执行resolve,输出实例成功态的vlaue属性:  420    return value + 100;}, (reason)=>{    // 失败时执行的回调    console.log('执行reject,输出实例失败态的reason属性: ', reason);     throw new Error('失败了');}).then((value)=>{    // then的成功回调里面输出,前一个then成功回调的返回值(即promise实例的value属性), 如果没有显示的return, 那么返回的是undefined    console.log('第二个then的成功回调里面输出,前一个then成功回调的返回值: ',value); // 第二个then的成功回调里面输出,前一个then成功回调的返回值:  520    return value + 200;}, (reason)=>{    console.log('第二个then的失败: ', reason);}).then((value)=>{    console.log('第三个then的成功回调里面输出,前一个then成功回调的返回值: ',value);  // 第三个then的成功回调里面输出,前一个then成功回调的返回值:  720});// => 		2秒后执行resolve,输出实例成功态的vlaue属性:  420		第二个then的成功回调里面输出,前一个then成功回调的返回值:  520		第三个then的成功回调里面输出,前一个then成功回调的返回值:  720复制代码
  • 源码
function Promise(executor){		let self 	= this;	    self.status = 'pending';  // pending => fulfilled | rejected	    self.value  = undefined;	    self.reason = undefined;	    self.onFulfilledCallbacks = [];     // 用于存放所有then方法成功态的回调	    self.onRejectedCallbacks = [];      // 用于存放所有then方法失败态的回调	    // 成功 	    function resolve(value){	        if(self.status === 'pending'){	            self.value  = value;	            self.status = 'fulfilled';	            self.onFulfilledCallbacks.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);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	    }catch(err){	        reject(err);	    }	}			Promise.prototype.then = function(onFulfilled, onRejected){	    let self = this;	    let promise2 = new Promise(function(resolve, reject){	        // console.log(this === self); // 这里因为使用了箭头函数,所以self === this, 指向同一个对象	        // 该executor函数会里面执行,因此把之前的状态判断及成功回调的代码移到此处与之前功能一样;	        // 需要说明的是这个promise需要根据上一个的状态和值进行判断,故而设置self变量用于引用上一个this	        if(self.status === 'fulfilled'){	            let x = onFulfilled(self.value); // 成功回调; 如果没有就当前对象的value属性值	            resolve(x);   // 将处理后的结果作为参数传递给promise实例的value属性; 同时也会传递给下一个then的成功回调	        }	    	        if(self.status === 'rejected'){	            try{	                let x = onRejected(self.reason);  // onRejected处理	                reject(x);	            }catch(e){	                reject(e);	            }	        }	    	        if(self.status === 'pending'){	            self.onFulfilledCallbacks.push(()=>{	                let x = onFulfilled(self.value);	                resolve(x);	            });	            self.onRejectedCallbacks.push(()=>{	                let x = onRejected(self.reason);	                reject(x);	            });	        }	    });	    return promise2;	};复制代码
  • 解析

    1. 异步和同步的处理方式几乎一致, 异步的无非就是在pending态时先把回调保存起来,待状态改变时再执行

Promise.prototype.then()的成功回调返回一个新的promise实例和执行executor时resolve一个新的promsie实例

采用链式的then,可以指定一组按照次序调用的回调函数; 此时前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用;

因此处逻辑\代码比较多,放在一起看了

  • 使用
let p = new Promise((resolve, reject)=>{	    resolve(1000);		// 或 resolve(new Promise((resolve, reject)=>{ resolve('成功');}))	});		p.then((value)=>{	    return new Promise((resolve, reject)=>{	        resolve(value + 500);	    });	}).then((value)=>{	    console.log(value);  // 1500	});复制代码
  • 源码
function Promise(executor){	    let self = this;	    this.status = 'pending';  // pending => fulfilled | rejected	    this.value  = undefined;	    this.reason = undefined;	    this.onFulfilledCallbacks = [];     // 用于存放所有then方法成功态的回调	    this.onRejectedCallbacks = [];      // 用于存放所有then方法失败态的回调		    // 成功 	    function resolve(value){	        // 如果value是个Promise实例, 就要先处理该promise实例	        /*	        let p = new Promise((resolve, reject)=>{	            resolve(new Promise(function(resolve, reject){	                resolve('成功');	            }));	        })	        */		        if(value instanceof Promise){	            return value.then((data)=>{	                resolve(data);	            },(y)=>{	                reject(y);	            });	        }			        if(self.status === 'pending'){	            self.value  = value;	            self.status = 'fulfilled';	            self.onFulfilledCallbacks.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);  // 该函数会在new Promise()实例时立即调用,它接收两个参数: resolve reject	    }catch(err){	        reject(err);	    }	    	}			function resolvePromise(x, promise2, resolve, reject){	    // 如果then的回调函数中返回之前的promsie,就有问题了(因为状态一旦改变就被冻结,不能再次变化))	    if(x === promise2){	        return reject(new TypeError('循环应用'));	    } 		    // 判断x是普通值还是对象,如果是普通值,直接resolve	    // 如果是对象或函数执行	    if((x !== null && typeof x === 'object') || typeof x === 'function'){	        // 这里可以是promise,然后尝试执行	        try {	            // 判断有没有then方法, 在获取then的过程中也可能会出错(比如某个对象的then属性get的时候抛出错误)	            /*	            let obj = {};	            Object.defineProperty(obj, 'then', {	                get(){	                    throw new Error('不让你get!');	                }	            });	            */	            let then = x.then;   // 获取x的then属性; 如果没有就会抛出错误	            if(typeof then === 'function'){	                then.call(x, (y)=>{	                    // y有可能也是一个promise	                    // 递归解析,直到结果是普通值为止	                    resolvePromise(y, promise2, resolve, reject);	                }, (r)=>{	                    reject(r);	                });	            } else {  	                // 有可能是普通对象或普通值 {
then: 'xbs'}或{
then: {}} resolve(x); } }catch(e){ // 没有then那可能就是一个普通对象{a:xxx} reject(e); } } else { resolve(x); } } Promise.prototype.then = function(onFulfilled, onRejected){ // .then().then().then()值的穿透, 因为我们在then没传回调参数时,手动给其添加了相应的回调函数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value=> value; onRejected = typeof onRejected === 'function' ? onRejected: err => {throw err}; let self = this; let promise2 = new Promise(function(resolve, reject){ // 该executor函数会立刻执行,因此把之前的状态判断及成功回调的代码移到此处与之前功能一样; // 需要说明的是这个promise需要根据上一个的状态和值进行判断,故而设置self变量用于引用上一个this if(self.status === 'fulfilled'){ // 这里要使用promise2, 所以需要增异步保证可以获取到promise2; // 为什么要使用promise2? - 因为每次then要返回的是一个新的promise, 如果有人要返回上一个promise呢, 这时候就需要去判断,promise2和x的关系 /* // 看这里就知道为什么要判断x与promise2的关系了 let p = new Promise((resolve,reject)=>{ resolve('成功'); }) p.then((value)=>{ return p; }); */ // 使用定时器是为了保障promise2能获取到; (先执行同步代码)异步代码(setTimeout是宏任务,主栈代码执行完毕,微任务执行后再执行)是在同步执行完成后执行,故而可以获取到promise2 setTimeout(function(){ // 为什么要try呢? 因为没人能保证樱花大道上没有狗狗的翔 /* let p = new Promise((resolve,reject)=>{ resolve('成功'); }) p.then((value)=>{ throw new Error('就欺负你怎么了'); // 成功态中抛错误,可谓防不胜防啊 }, (reason)=>{ // 失败回调... }) */ try { let x = onFulfilled(self.value); // 如果此次x是返回的新的promise如何处理? // 采用统一的方法来处理x,判断x是promise还是普通值 resolvePromise(x, promise2, resolve, reject); } catch(err) { // 如果执行函数时抛出失败 那么会走向下一个then的失败状态 reject(err); } }, 0); } if(self.status === 'rejected'){ setTimeout(function(){ try { let x = onRejected(self.reason); // onRejected处理 resolvePromise(x, promise2, resolve, reject); } catch(err) { // 如果执行函数时抛出失败 那么会走向下一个then的失败状态 reject(err); } }, 0) } if(self.status === 'pending'){ // 异步的处理在这里 // 因为需要待异步执行完成后调用执行,而何时调用并不知道; 因此要先存起来(订阅),待状态改变再执行(发布) self.onFulfilledCallbacks.push(()=>{ setTimeout(()=>{ // 同样也会遇到成功态回调里面抛出错误的情况,所以也要try{}catch(){}一下 try{ let x = onFulfilled(self.value); resolve(x); }catch(err){ reject(err); } },0); }); self.onRejectedCallbacks.push(()=>{ setTimeout(()=>{ // 同样也会遇到成功态回调里面抛出错误的情况,所以也要try{}catch(){}一下 try{ let x = onRejected(self.reason); reject(x); }catch(err){ reject(err); } },0); }); } }); return promise2; };复制代码
  • 解析

其实到这里,Promise的核心已经实现了


Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数

  • 使用
getJSON('/posts.json').then(function(posts) {	  // ...	}).catch(function(error) {	  // 处理 getJSON 和 前一个回调函数运行时发生的错误	  console.log('发生错误!', error);	});复制代码
  • 源码
Promise.prototype.catch = function(errCallback){	    return this.then(null, errCallback);	};复制代码

Promise.all

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例

  • 使用
let p1 = new Promise((resolve, reject)=>{	    resolve('p1-success!');	});		let p2 = new Promise((resolve, reject)=>{	    setTimeout(()=>{	        resolve('p2-success!');	    }, 2000);	});		let p3 = new Promise((resolve, reject)=>{	    setTimeout(()=>{	        resolve('p3-success!');	    }, 3000);	});		let p = Promise.all([p1, p2, p3]).then((result)=>{	    console.log(result);	// [ 'p1-success!', 'p2-success!', 'p3-success!' ]	});复制代码
  • 源码
Promise.all = function(values){	    return new Promise(function(resolve, reject){	        let results = [];	// 存放结果	        let index = 0;		// 处理方法执行了几次	        function processData(resIndex, data){	            index++;	            results[resIndex] = data;		// 将执行结束后的结果存放到结果数组(因为结果和执行顺序有严格对应关系,所以不能用push,用arr[0] = value的形式);	            if(index === values.length){	                resolve(results); 		// 当结果数组和执行操作的数量一样时,将结果返回	            }	        }	        	        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); // 如果是普通值,直接返回	            }	        }	    });	};复制代码
  • 解析

    1. Promise.all的实现原理的核心是计数器

Promise.race

  • 使用
let p1 = new Promise((resolve, reject)=>{	    resolve('p1-success!');	});		let p2 = new Promise((resolve, reject)=>{	    setTimeout(()=>{	        resolve('p2-success!');	    }, 2000);	});		let p3 = new Promise((resolve, reject)=>{	    setTimeout(()=>{	        resolve('p3-success!');	    }, 3000);	});		let p = Promise.race([p1, p2, p3]).then((result)=>{	    console.log(result); //'p1-success!'	});复制代码
  • 源码
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'){	                current.then(resolve,reject);	            } else {	                resolve(current);	            }	        }	    });	};复制代码

Promise.resolve()

Promise.resolve 可以将现有对象转换为Promise对象

  • 使用
let p = Promise.resolve(300);	console.log(p instanceof Promise); // true复制代码
  • 源码
Promise.resolve = function(value){	    return new Promise(function(resolve,reject){	        resolve(value);	    });	};复制代码

Promise.reject()

Promise.reject 可以将现有对象转换为Promise对象

  • 使用
let p = Promise.reject(300);	console.log(p instanceof Promise); // true复制代码
  • 源码
Promise.reject = function(reason){	    return new Promise(function(resolve,reject){	        reject(reason);	    });	};复制代码

结语

先告一段落啦, 因理解能力有限, 难免会有遗漏和偏差,如果您发现了请告知! 学习和成长的路上看了很多大佬的博客\视频\文档\代码,一直在消费大佬的辛苦成果,自己写一写,算是向大佬致敬了!

转载于:https://juejin.im/post/5ca0d0c051882567e32fc459

你可能感兴趣的文章