一个promise的当前状态只能是pending、fulfilled和rejected三种之一。状态改变只能是pending到fulfilled或者pending到rejected。状态改变不可逆。git
支持链式调用。github
(1) 原型方法面试
Promise.prototype.then = function() {} Promise.prototype.catch = function() {}
(2) 静态方法promise
Promise.resolve = function() {} Promise.reject = function() {} Promise.all = function() {} Promise.race = function() {} //...
Promise的优缺点
优势:
状态不可改变
链式调用解决回调地狱问题,让代码更清晰,更易维护。
缺点:
不能在执行中停止
在pending中不能查看异步到什么状态了。异步
首先咱们先看看咱们怎么使用Promise的函数
new Promise(function (resolve, reject) { setTimeout(() => { // resolve("异步成功拉"); reject("异步失败啦"); }, 1000); }).then( function (data) { console.log(data); /* then里面能够是同步的代码,也能够是异步的promise */ // return new Promise(function (resolve, reject){ // setTimeout(() => { // resolve("第一个then里面的异步"); // }, 1000); // }); return "链式调用第一个then的返回值"; }, function (reason) { console.log("第一个then" + reason); return "第一个then reject 后的 失败 reason" } )
function Promise(executor) { var _this = this; this.data = undefined;//数据 this.status = "pending";//状态 this.onResolvedCallback = [] // Promise resolve时的回调函数集,由于在Promise结束以前有可能有多个回调添加到它上面 this.onRejectedCallback = [] // Promise reject时的回调函数集,由于在Promise结束以前有可能有多个回调添加到它上面 var resolve = function (data){ if (_this.status === "pending"){ _this.status = "resolved"; _this.data = data; for(var i = 0; i < _this.onResolvedCallback.length; i++) { _this.onResolvedCallback[i](data) } } } var reject = function (errReason) { if (_this.status === "pending"){ _this.status = "rejected"; _this.data = errReason; for(var i = 0; i < _this.onRejectedCallback.length; i++) { _this.onRejectedCallback[i](errReason) } } } try{ executor(resolve, reject); } catch(e){ reject(e); } }
由上面的代码能够看出 executor通常来讲应该是一个异步,等待其执行完后 成功或者失败,而后执行其回调resolve或者reject。 而后在resolve或者reject里面执行then里面注册的回调函数。因此then函数应该是一个注册用户回调 到 onResolvedCallback或者onRejectedCallback里的过程。测试
在实现的then函数以前,咱们来明确一下then函数要作那几件事情。
一、注册用户回调到 _this.onResolvedCallback 或者 _this.onRejectedCallback
二、支持链式调用, 其实就是then函数执行完后应该返回一个promise对象,而且根据promise A+标准,这个promise应该是一个新的promise。
三、处理三种状态, executor多是一个同步的函数也有多是一个异步的函数,因此在执行then的时候 _this.status 多是pending(executor是异步的状况),_this.status 多是resolve/reject (executor是同步的状况)
而status是pending的状况下是一个注册的过程,也就是将回调存起来,等待status变成resolve或者reject再执行回调。
而status是resolve/reject的状况下就直接执行对调了。
上面这段解释建议边看下面的代码边理解上面这段话this
//onResolved onRejected 为调用者传进来的 成功和失败的回掉 Promise.prototype.then = function (onResolved, onRejected){ var _this = this var promise2; // 根据标准,若是then的参数不是function,则咱们须要忽略它,此处以以下方式处理 onResolved = typeof onResolved === 'function' ? onResolved : function(value) {} onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {} //若是上面的executor是一个异步的,执行then的时候 status必定是pending if (this.status === "pending"){ //生成一个新的promise promise2 = new Promise(function(resolve, reject) { //将调用者的回调包装后注册进promise的回调队列 _this.onResolvedCallback.push(function (value){ //这里的value是在onResolvedCallback里面的函数执行时传的 try { var x = onResolved(_this.data) if (x instanceof Promise) { //then里面的回调若是是异步的promise,则等待异步执行完后,再进入promise2的then中注册的回调 x.then(resolve, reject); } else{ //若是是同步的,直接进入promise2的then中注册的回调 resolve(x); } } catch (e) { reject(e) } }); _this.onRejectedCallback.push(function (reason) { try { var x = onRejected(_this.data) if (x instanceof Promise) { x.then(resolve, reject); } else{ reject(x); } } catch (e) { reject(e) } }); }) return promise2; } //若是executor是同步的, 则执行then的时候 status为 resolved或者rejected if (_this.status === 'resolved') { // 若是promise1(此处即为this/_this)的状态已经肯定而且是resolved,咱们调用onResolved // 由于考虑到有可能throw,因此咱们将其包在try/catch块里 return promise2 = new Promise(function(resolve, reject) { try { var x = onResolved(_this.data) if (x instanceof Promise) { // 若是onResolved的返回值是一个Promise对象,直接取它的结果作为promise2的结果 x.then(resolve, reject) } resolve(x) // 不然,以它的返回值作为promise2的结果 } catch (e) { reject(e) // 若是出错,以捕获到的错误作为promise2的结果 } }) } // 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就再也不作过多解释 if (_this.status === 'rejected') { return promise2 = new Promise(function(resolve, reject) { try { var x = onRejected(_this.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) } }
看完代码后我继续来解释promise2中的处理过程,如今须要想的是如何在 promise2中如何执行完后如何将正确的数据交给下一个then。
因此须要判断x(onResolved或者onRejected执行的结果)是一个什么值,若是是一个普通的值则直接调用promise2的resolve或者reject,可是若是x是一个promise对象,则咱们须要等待这个promise对象状态变成reosolve或者reject,也就是等待这个promise处理完异步任务(须要用到promise,里面通常都是异步任务),因此调用x.then(resove,reject),这里是直接将promise2的resolve/reject做为回调的。也就是等待x这个promise对象执行完后,交给promise2的then里面的回调,衔接整个链式的过程。prototype
Promise.prototype.catch = function (onRejected) { return this.then(null, onRejected) }
到此,promise的整个原理就算大部分完成了,其实理解起来并非那么难,对不对。code
根据promise A+规范,上面在promise2中处理x并将处理值交给 promise2.then的回调的整个过程并无考虑到''不符合promise规范的对象并带有then方法的状况'',promise A+规范但愿能以最保险的方式将x传递到promise2.then,即便x是一个不遵循promise规范,可是带有then的对象也可以完美的处理。
因此须要对x更进一步的处理,而后将数据交给下一步
/即咱们要把onResolved/onRejected的返回值,x,
当成一个多是Promise的对象,也即标准里所说的thenable,
并以最保险的方式调用x上的then方法,若是你们都按照标准实现,
那么不一样的Promise之间就能够交互了。而标准为了保险起见,
即便x返回了一个带有then属性但并不遵循Promise标准的对象/
递归解决,只要x带有then方法,就会像剥洋葱同样层层的剥开,直到x是一个非相似promise的这种处理异步的对象,非thennable对象。
function resolvePromise(promise2, x, resolve, reject) { var then var thenCalledOrThrow = false if (promise2 === x) { // 对应标准2.3.1节 return reject(new TypeError('Chaining cycle detected for promise!')) } if (x instanceof Promise) { // 对应标准2.3.2节 // 若是x的状态尚未肯定,那么它是有可能被一个thenable决定最终状态和值的 // 因此这里须要作一下处理,而不能一律的觉得它会被一个“正常”的值resolve if (x.status === 'pending') { x.then(function(value) { resolvePromise(promise2, value, resolve, reject) }, reject) } else { // 但若是这个Promise的状态已经肯定了,那么它确定有一个“正常”的值,而不是一个thenable,因此这里直接取它的状态 x.then(resolve, reject) } return } if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { // 2.3.3 try { // 2.3.3.1 由于x.then有多是一个getter,这种状况下屡次读取就有可能产生反作用 // 即要判断它的类型,又要调用它,这就是两次读取 then = x.then if (typeof then === 'function') { // 2.3.3.3 then.call(x, function rs(y) { // 2.3.3.3.1 if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准 thenCalledOrThrow = true return resolvePromise(promise2, y, resolve, reject) // 2.3.3.3.1 }, function rj(r) { // 2.3.3.3.2 if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准 thenCalledOrThrow = true return reject(r) }) } else { // 2.3.3.4 resolve(x) } } catch (e) { // 2.3.3.2 if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准 thenCalledOrThrow = true return reject(e) } } else { // 2.3.4 resolve(x) } }
将promise2的处理过程改一下,三种状况都要改。
promise2 = new Promise(function(resolve, reject) { //将调用者的回调包装后注册进promise的回调队列 _this.onResolvedCallback.push(function (value){ //这里的value是在onResolvedCallback里面的函数执行时传的 try { var x = onResolved(value); //解决调用者定义的onResolved的返回值 x 是非规范的Promise对象且带有then方法的状况 resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e) } }); _this.onRejectedCallback.push(function (reason) { try { var x = onRejected(reason) resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e) } }); }) return promise2;
测试一下
//测试不遵照promise的对象,且带有then方法 var notPromise = function () { // } notPromise.prototype.then = function (onResolved, onRejected) { setTimeout(function () { onResolved("不遵照promise规范的对象") }, 1000) } //测试 new Promise(function (resolve, rejected) { setTimeout(function () { resolve("异步开始了"); },1000) }).then(function (data) { console.log(data); //下面的返回能够是 promise 也能够是普通的值, 还能够是不许寻promise规范的对象但带有then方法(在resolve都给与了支持) //普通值和promise就不测试了。 //测试一下遵循promise的对象, 且带有then方法 return new notPromise(); }).then(function (data) { //在then里面 会把上一个传递下来的值(new notPromise())不断的调它的then方法,知道肯定没有then能够调用了,就递交到下一个then console.log(data); // 这里的 data 不是 (new notPromise())而是它的then方法返回的。 })
new Promise(resolve=>resolve(8)) .then() .catch() .then(function(value) { alert(value) })
跟下面这段代码的行为是同样的
new Promise(resolve=>resolve(8)) .then(function(value){ return value }) .catch(function(reason){ throw reason }) .then(function(value) { alert(value) })
不传回调,则使用默认回调,因此在默认回调上改改,让它将值传递下去
onResolved = typeof onResolved === 'function' ? onResolved : function(value) {return value} onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {throw reason}
在一些场景下,咱们可能会遇到一个较长的Promise链式调用,在某一步中出现的错误让咱们彻底没有必要去运行链式调用后面全部的代码,相似下面这样(此处略去了then/catch里的函数):
先给出结果
Promise.cancel = Promise.stop = function() { return new Promise(function(){}) } //下面咱们来尝试一下,若是遇到错误,则不会执行alert(1) new Promise(function(resolve, reject) { resolve(42) }) .then(function(value) { var isErr = true; //尝试更改为 true 或者 false 看alert(1);是否执行 if (isErr){ // "Big ERROR!!!" return Promise.stop() } }) //值的穿透 .catch() .then() .then() .catch() .then(function () { alert(1); })
return new Promise(function(){})这段话就意味着x是一个promise对象, 则必定会走 x。then(resolve,reject) 交给promise2的then。可是这里new Promise(function(){}根本就没有resolve或者reject,因此它的状态一直为pending, 因此永远不会执行 x.then(resolve,reject)里面的resolve/reject,那么状态就传递不下去,链式就算是断开了。
没有错误处理函数,就给个默认的错误处理
function reject(reason) { setTimeout(function() { if (_this.status === 'pending') { _this.status = 'rejected' _this.data = reason if (_this.onRejectedCallback.length === 0) { console.error(reason)//默认的错误处理 } for (var i = 0; i < _this.rejectedFn.length; i++) { _this.rejectedFn[i](reason) } } }) }
列几个比较经常使用,很好理解,看代码基本就能明白,特别是Promise.all Promise.race的实现哦,面试常考原理。
Promise.all = function(promises) { return new Promise(function(resolve, reject) { var resolvedCounter = 0 var promiseNum = promises.length var resolvedValues = new Array(promiseNum) for (var i = 0; i < promiseNum; i++) { (function(i) { Promise.resolve(promises[i]).then(function(value) { resolvedCounter++ resolvedValues[i] = value if (resolvedCounter == promiseNum) { return resolve(resolvedValues) } }, function(reason) { return reject(reason) }) })(i) } }) } Promise.race = function(promises) { return new Promise(function(resolve, reject) { for (var i = 0; i < promises.length; i++) { Promise.resolve(promises[i]).then(function(value) { return resolve(value) }, function(reason) { return reject(reason) }) } }) } Promise.resolve = function(value) { var promise = new Promise(function(resolve, reject) { resolvePromise(promise, value, resolve, reject) }) return promise } Promise.reject = function(reason) { return new Promise(function(resolve, reject) { reject(reason) }) }
try { module.exports = Promise } catch (e) {} function Promise(executor) { var self = this self.status = 'pending' self.onResolvedCallback = [] self.onRejectedCallback = [] function resolve(value) { if (value instanceof Promise) { return value.then(resolve, reject) } setTimeout(function() { // 异步执行全部的回调函数 if (self.status === 'pending') { self.status = 'resolved' self.data = value for (var i = 0; i < self.onResolvedCallback.length; i++) { self.onResolvedCallback[i](value) } } }) } function reject(reason) { setTimeout(function() { // 异步执行全部的回调函数 if (self.status === 'pending') { self.status = 'rejected' self.data = reason for (var i = 0; i < self.onRejectedCallback.length; i++) { self.onRejectedCallback[i](reason) } } }) } try { executor(resolve, reject) } catch (reason) { reject(reason) } } function resolvePromise(promise2, x, resolve, reject) { var then var thenCalledOrThrow = false if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise!')) } if (x instanceof Promise) { if (x.status === 'pending') { //because x could resolved by a Promise Object x.then(function(v) { resolvePromise(promise2, v, resolve, reject) }, reject) } else { //but if it is resolved, it will never resolved by a Promise Object but a static value; x.then(resolve, reject) } return } if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { try { then = x.then //because x.then could be a getter if (typeof then === 'function') { then.call(x, function rs(y) { if (thenCalledOrThrow) return thenCalledOrThrow = true return resolvePromise(promise2, y, resolve, reject) }, function rj(r) { if (thenCalledOrThrow) return thenCalledOrThrow = true return reject(r) }) } else { resolve(x) } } catch (e) { if (thenCalledOrThrow) return thenCalledOrThrow = true return reject(e) } } else { resolve(x) } } Promise.prototype.then = function(onResolved, onRejected) { var self = this var promise2 onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v } onRejected = typeof onRejected === 'function' ? onRejected : function(r) { throw r } if (self.status === 'resolved') { return promise2 = new Promise(function(resolve, reject) { setTimeout(function() { // 异步执行onResolved try { var x = onResolved(self.data) resolvePromise(promise2, x, resolve, reject) } catch (reason) { reject(reason) } }) }) } if (self.status === 'rejected') { return promise2 = new Promise(function(resolve, reject) { setTimeout(function() { // 异步执行onRejected try { var x = onRejected(self.data) resolvePromise(promise2, x, resolve, reject) } catch (reason) { reject(reason) } }) }) } if (self.status === 'pending') { // 这里之因此没有异步执行,是由于这些函数必然会被resolve或reject调用,而resolve或reject函数里的内容已经是异步执行,构造函数里的定义 return promise2 = new Promise(function(resolve, reject) { self.onResolvedCallback.push(function(value) { try { var x = onResolved(value) resolvePromise(promise2, x, resolve, reject) } catch (r) { reject(r) } }) self.onRejectedCallback.push(function(reason) { try { var x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (r) { reject(r) } }) }) } } Promise.prototype.catch = function(onRejected) { return this.then(null, onRejected) } Promise.deferred = Promise.defer = function() { var dfd = {} dfd.promise = new Promise(function(resolve, reject) { dfd.resolve = resolve dfd.reject = reject }) return dfd }
https://github.com/ab164287643/Promise3/blob/master/Promise3.js