原文地址fancierpj0.github.io/iPromise/

目录 (づ ̄ 3 ̄)づ=> 掘金这目录页。。放这么角落。。嗯。。干撒呢

[TOC]

本文会对Promise规范进行一个比较完整的实现,目的是为了加深对Promise各个特性的理解从而更好的应用。

[warning] 注意:本文依据Promises/A+规范进行Promise的实现

1.Promise/A+ 术语

1.1. promise

promise是一个对象或则函数,它的表现是依据Promises/A+这篇规范说明来定义的。

1.1. promise is an object or function with a then method whose behavior conforms to this specification.

1.2. theable

thenable是一个定义了then方法的对象或则函数。

thenable is an object or function that defines a then method.

1.3. value

value可以是任何合法的JS值,甚至包括undefined、一个thenable、一个promise。

value is any legal JavaScript value (including undefined, a thenable, or a promise).

1.4. exception

exception是一个用throw语句抛出的值。

exception is a value that is thrown using the throw statement.

1.5. reason

reason是一个为什么promise会被拒绝的理由。

reason is a value that indicates why a promise was rejected.

Promise规范要求

判断一个东东是不是Promise,有三项主要的特征可作为参考

  • Promise有三种状态 pendingfulfilledrejected
  • Promise含有then方法
  • Promise含有Promise Resolution Procedure (promise的状态转换处理方法)。

2.1. Promise状态

一个promise必须处于 pending 、fulfilled、rejected 三种状态中的其中一种

下面是一个promise最基本的使用demo,我们先有个印象。

  • 其中promise实例化的时候传入了一个函数作为参数,这个函数我们称之为 executor ,它能告诉我们何时将promise状态从pending转化为其余两态中的一态。
  • then 方法是实例化对象下的一个方法,它能传入两个参数,一般是两个回调函数,对应fulfilled和rejected两个状态,当promise从pengding状态转化成其中一个状态时就会触发对应的回调函数。
let p = new Promise((resolve,reject)=>{let x = Math.random();console.log(x);if (x > .5) {resolve('我是你许下的诺言的那个东东');} else {reject('我是你未能实现诺言的理由');}
});p.then((value)=>{ //绑定成功时的回调函数console.log('fulfilled:',value); //fulfilled:我是你许下的诺言的那个东东
},(reason)=>{ //绑定失败时的回调函数console.log('rejected:',reason); //rejected:我是你未能实现诺言的理由
});
复制代码

2.1.1. pending状态

当Promise处于pending状态时,它可能转换为fulfilled或则rejected状态。

When pending, a promise:may transition to either the fulfilled or rejected state.

2.1.2. fulfilled状态

当Promise处于fulfilled状态时,它不再能转换为其它状态 且 它必须有一个值,这个值不能被更改。

When fulfilled, a promise:

  • must not transition to any other state.
  • must have a value, which must not change.

2.1.3 rejected状态

当promise处于rejected时,它不再能转换为其它状态 且 它必须有一个理由,这个理由不能被更改。

When rejected, a promise:

  • must not transition to any other state.
  • must have a reason, which must not change.

[danger]注意: 当promise处于fulfilled或则rejected时,它都有一个值,这个值不能被更改,但是可以像使用常量一样在这个值下面挂载其它值。

Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.

2.1. Promise实现

请先回顾一下我们在说Promise状态时候最初的那个demo 我们通过实例化Promise时传入了一个参数,这个参数是一个执行函数(executor),它能决定什么时候将Promise转换成fulfilled什么时候转换成rejected。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';function Promise(executor){let self = this; //缓存下self.value = undefined; //用来存放value和reason,因为promise只会处于一种状态故可只用一个变量来表示。self.status = PENDING; //将初始状态设置为pendingself.onFulfilledCallbacks = []; //用来存放所有成功的回调函数self.onRejectedCallbacks = []; //用来存放所有失败的回调函数try{executor(resolve,reject); //调用执行函数,将resolve和reject方法作为参数传入}catch (e){reject(e); //若执行函数中存在异常直接用抛出的值来拒绝promise}//-----------------------------------------------------------------------------------------------------------function resolve(value){ //此方法会随着executor传入而传入setTimeout(function(){if(self.status === PENDING){ //确保状态只会改变一次self.status = FULFILLED; //改变状态self.value = value; //赋予一个值self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.2. //2.2.6.}})}function reject(reason){setTimeout(function(){if(self.status === PENDING){self.status = REJECTED;self.value = reason;self.onRejectedCallbacks.forEach(cb => cb(self.value));}})}
}复制代码

以上实现了2.1. ,promise的三种状态以及状态之间的改变。

executor,形参、实参、作用域链

我们可以发现最终转换状态时通过Promise内部的两个方法resolve和reject,这个两个方法是在什么时候传入的呢? 一个函数的参数查找,是从调用这个函数时所处的作用域开始查找的。 new Promise传入的executor,是参数也是对executor函数的定义,此时executor的resolve和reject为形参。 我们new Promise的时候,会执行构造函数Promise内的代码,也就是在这时executor被执行,而executor此时所处的作用域是在Promise构造函数内部,resolve和reject方法作为实参被传入。

2.2. then方法

一个promise必须提供一个then方法来使用它将要或则说已经被赋予的 value 或则 reason,一个promise的then方法接收两个参数

promise.then(onFulfilled,onRejected)
复制代码

2.2.1. then参数

then中的参数皆为可选参数,如果onFulfilled或则说onRejected不是一个函数,那么将会被忽略。

Both onFulfilled and onRejected are optional arguments:

  • If onFulfilled is not a function, it must be ignored.
  • If onRejected is not a function, it must be ignored.

2.2.2. 如果onFulfilled是一个函数

  • 如果onFulfilled是一个函数,它必须在promise状态转换为fulfilled时候就被调用,并且promise被赋予的value会成为这个函数(onFulfilled)的第一个参数。
  • onFulfilled不能在promise状态转化为fulfilled前就调用
  • onFulfilled函数不能重复调用

原文规范详见Promises/A+

2.2.3. 如果onRejected是一个函数

  • 如果onRejected是一个函数,它必须在promise状态转换为rejected时候就被调用,并且promise被赋予的reason会成为这个函数(onRejected)的第一个参数。
  • onRejected不能在promise状态转化为rejected前就调用
  • onRejected函数不能重复调用

2.2.4. onFulfilled 或则 onRejected 必须在执行栈 只存在 platform code 时才能被调用。

2.2.5. onFulfilled 和 onRejected 必须被当做函数调用。

2.2.6. 同一个promise实例可以调用多次then

  • 当一个promise转化为fulfilled状态,所有onFulfilled callback会按照回调函数通过then添加时的顺序而执行。
  • 当一个promise转化为rejected状态,所有onRejected callback会按照回调函数通过then添加时的顺序而执行。

:then在同一个promise实例下多次调用,意味着可以在同一个promise的同一种状态下绑定多个不同的回调函数,而这些回调函数执行的顺序和它们被绑定时的顺序相同。

2.2.7. then必会返回一个新的promise

promise2 = promise1.then(onFulfilled,onRejected);
复制代码
  • 如果onFulfilled或onRejected回调函数中返回了一个值,假定为x,那么调用一个 promise解析方法 [[Resolve]](promise2,x)
  • 如果onFulfilled或者onRejected抛出了一个 exception(异常) e , promise2 必须以这个e作为reason来拒绝promise,使其状态改变为rejected。
  • 如果onFulfilled不是一个函数且 promise1 的状态为fulfilled,promise2必须以 promise1 的值来fulfilled。
  • 如果onRejected不是一个函数且 promise1 的状态为rejected,promise2必须以 promise1 的理由来rejected。

2.2. Promise实现

2.2.提的是一个then的实现规则,而then主要作用为promise绑定回调函数,当promise转换状态时会自动调用对应的回调函数。(对应规范2.2.2-2.2.3) 其实就是发布订阅模式啦

function Promise(){...function resolve(value){ setTimeout(function(){ //2.2.4.if(self.status === PENDING){ //2.2.2.3-2.2.2.4self.status = FULFILLED; self.value = value; self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.6.}})}function reject(reason){setTimeout(function(){if(self.status === PENDING){ //2.2.3.3-2.2.3.4self.status = REJECTED;self.value = reason;self.onRejectedCallbacks.forEach(cb => cb(self.value));}})}
}
//---------------------------------------------------------------------------------------------------
Promise.prototype.then = function (onFulfilled, onRejected) { //2.2.1.//2.2.7.3-2.2.7.4 //2.2.5.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};let self = this,promise2; //2.2.7.0 //声明要返回的promise2if(self.status === PENDING){//2.2.7.return promise2 = new Promise(function(resolve,reject){//存储then方法绑定的回调函数 //2.2.6.self.onFulfilledCallbacks.push((value)=>{try{let x = onFulfilled(value);resolvePromise(promise2,x,resolve,reject); //2.2.7.1}catch (e){reject(e); //2.2.7.2}});self.onRejectedCallbacks.push((reason)=>{try{let x= onRejected(reason);resolvePromise(promise2,x,resolve,reject);}catch (e){reject(e);}});});}
};
复制代码

关于platform code

Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

上面一大段话的意思大致上就是要求 onFulfilledonRejected 回调函数确保异步执行。我们可以选择用宏任务(setTimeout/setImmediate)或则微任务(process.nextTix/MutationObserver)来完成这项规范。

这里我们通过在Promise中的resolve和reject方法中套了一个setTimeout()来实现。

 function resolve(value){ setTimeout(function(){ //2.2.4.if(self.status === PENDING){ //2.2.2.3-2.2.2.4self.status = FULFILLED; self.value = value; self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.6.}})}
复制代码

这样setTimeout中的代码就会在下一个新的执行栈中执行。即使executor中的代码是同步代码也一样

let p = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('resolve');})
});
p.then((value)=>{console.log('fulfilled:',value);
},(reason)=>{console.log('rejected:',reason);
});
console.log('----------------');//输出
>>>----------------
>>>fulfilled: resolve
//----------------------------------------------------------------------------------
let p = new Promise((resolve,reject)=>{resolve('resolve');
});
p.then((value)=>{console.log('fulfilled:',value);
},(reason)=>{console.log('rejected:',reason);
});
console.log('----------------');//输出
>>>----------------
>>>fulfilled: resolve
复制代码

情景:值的穿透

下面的例子中本应是第一个then中的参数会穿透到第二then中作为参数。 下面两句再集合resolvePromise方法即是穿透原因

Promise.prototype.then = function (onFulfilled, onRejected) { //2.2.1.//2.2.7.3-2.2.7.4 //2.2.5.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; //结合resolvePromise方法即是穿透原因onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}; //继续把异常往后抛...//-------------------------------------------------
let p = new Promise((resolve,reject)=>{resolve('resolve');
});
p.then().then((value)=>{console.log(value); //会输出resolve
});
复制代码

2.3. Promise状态解析方法(promise resolution procedure)

let x= onRejected(reason);
resolvePromise(promise2,x,resolve,reject); //resolve/reject为promise2的resolve/reject
复制代码

Promise状态解析方法的作用是将then时返回的promise2的状态改变并赋予其vlaue/reason。

  • 如果 x 是一个thenable,那么该方法将试图将以 x 的状态来改变 promise2 的状态
  • 否则就将 promise2 改成 fulfilled 状态,并且value即为 x 的值

2.3.1. 如果 promise2x 是引用关系,则抛出一个 TypeError 做为理由来 reject promise2。

2.3.2. 如果 x 是一个promise ,让promise2采用它的状态。

  • 如果 x 处于pending,promise2 必须保持pending直到 x 转换为 fulfilled或则rejected。
  • 如果 xfulfilled状态,让promise2也为fulfilled,并且让promise2的value为x的value。
  • 如果 xrejected状态,让promise2也为rejected,并且让promise2的value为x的reason。

2.3.3. 如果 x 是一个对象或则函数

  • Let then be x.then
  • 如果检索 x.then 时候抛出了一个异常e,那么以这个 erejecte promise2。
  • 如果 then 是一个函数,用x作为thisresolvePromise作为第一个参数,rejectPromise作为第二个参数来 call它。
    • 如果resolvePromise被调用,循环调用 promise状态解析方法(原本的x替换为调用resolvePromise传入的参数,假定为y)。
    • 如果rejectPromise被调用,则reject Promise2,reason为调用rejectPromise传入的参数
    • 如果resolvePromiserejectPromise 同时被调用或则多次调用,那么第一个调用的拥有优先权,其它的会被忽略。
    • 如果调用 then 的时候抛出了一个异常 e
      • 如果 resolvePromiserejectPromise 已经被调用,则忽略它。
      • 否则,则用这个ereject promise2。
  • 如果then不是一个函数,则用xfulfilledpromise2

2.3.4. 如果 x 不是一个函数也不是一个对象,则用xfulfilledpromise2

2.3.3. Promise实现

resolvePromise方法针对的是then绑定的回调函数中的return值进行解析,一般情况是:

  • 当return的是普通类型的值,那么会以这个值来fulfilled promise2
  • 如果是一个promise,那么会以这个x promise的结果来fulfilled/rejected promise2
function resolve(value) {if(value instanceof Promise){ //和resolvePromise有点联系的是 当then return的promise中又resolve了一个promise会先走这,会将resolve里的promise的值赋给调用resolve的promise(说法欠妥,意会即可)return value.then(resolve,reject); //这意味着如果promise1 resolve中是一个promise2,那么promise1状态的改变时间会被推迟,直到promise2状态改变调用promise2的回调时,promise1状态才会改变才会触发promise1的回调}
...
//---------------------------------------------------------------------------------------------------------
function resolvePromise(promise2,x,resolve,reject){if(x === promise2){ //2.3.1.return reject(new TypeError('禁止循环引用!'));}let called =false;//2.3.2.if(x instanceof Promise){if(x.status === PENDING){ //2.3.2.1x.then((y)=>{resolvePromise(promise2,y,resolve,reject); //因为此时的y,有可能也是一个promise //挂上一个钩子只要x状态转化为成功态就递归调用resolvePromise},reject);}else{ //此分支存在的意义在于若executor调用resolve/reject不是异步的且不在resolve/reject中设置setTimeout,意味着当new的时候就会返回一个带状态的promise就会走这里。x.then(resolve,reject); //2.3.2.2-2.3.2.3 //只要x状态改变,就以x的状态和值来改变promise2的状态和值 //这个值可能是一个promise,前提是在上面那种假设实现中 //如果不符合上面那种实现且不想像规范一样允许值可以为一个promise或则对象 可除去此分支}}else if(x!=null&&((typeof x === 'function')||(typeof x === 'object'))){ //2.3.3.try{let then = x.then; //2.3.3.1if(typeof then === 'function'){//2.3.3.3.then.call(x,(y)=>{if(called) return; //2.3.3.3.3.called = true;resolvePromise(promise2,y,resolve,reject); //在resolve中又包含promise的情况下,由于resolve中的 value.then存在,当前回调调用时,resolve中的promise状态一定已经改变,在状态已经改变的时候利用then绑定回调,会走then中的status==fulfilled或则rejected分支},(reason)=>{if(called) return;called = true;reject(reason);});}else{resolve(x); //2.3.3.4. //1.3}}catch (e){if(called) return; //2.3.3.3.4.1.called = true;reject(e); //2.3.3.2. //2.3.3.3.4.2.}}else{ //2.3.4.resolve(x);}
}
复制代码

情景:当return的是promise且该promise的resolve/reject ()中 也是一个promise

let p = new Promise((resolve,reject)=>{resolve('resolve1');
});
p.then((value)=>{return new Promise((resolve,reject)=>{resolve(new Promise((resolve,reject)=>{setTimeout(()=>{resolve('别怂')});}));});
}).then((value)=>{console.log(value); //别怂
});
console.log('----------------');
复制代码

可见最终的value值为最里层的value值,这样的实现关键在于递归调用resolvePromise。

...
function resolve(value) {if(value instanceof Promise){ return value.then(resolve,reject);
...if(x instanceof Promise){if(x.status === PENDING){ //2.3.2.1x.then((y)=>{resolvePromise(promise2,y,resolve,reject); },reject);}else{x.then(resolve,reject); }}复制代码

以上这段代码,当promise1执行回调的时候,会将x传入resolvePromise执行,此时由于resolve()方法中的setTimeout,该x是pending状态进pending分支,该分支会为X挂上一个钩子,当它状态转换后会再次调用resolvePromise。

  • 如果x的resolve中传入的也是一个promise (y),由于resolve中添加的value.then,它会推迟x的状态转换,这意味着X状态转换时,y的状态一定已经转换,于是会走下面那个分支,调用y.then,而因为y的状态已经转换,在then方法中此时就不再能通过状态改变时触发回调函数,故要支持此功能需要在then中添加self.status===FULFILLED/REJECTED分支。
}else if(self.status === FULFILLED){return promise2 = new Promise(function(resolve,reject){setTimeout(function(){try{let x =onFulfilled(self.value);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}})});}else{return promise2 = new Promise(function(resolve,reject){setTimeout(function(){try{let x =onRejected(self.value);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}})});}
复制代码

这里用了setTimeout是为了确保回调函数会异步执行。(针对2.2.4.)

  • 如果x的resolve传入的只是一个普通的值。。。呵呵哒,那就直接resolve(x)咯

[warning] 值得注意的是: 如果没有在 resolve() 方法中对value进行判断,那么此时嵌套promise中再嵌套一层promise输出结果会是一个promise。因为第二个promise不会等第三个promise状态转换后才转换状态,这意味着第二个promise的值就为第三个promise对象。

情景:当new的promise中的resolve也是一个promise,而这个promise的resolve中又是一个promise...

此时情况同上个情景,得益于then()中对value的判断,它会推迟父promise状态的转变。 如果没有这个判断和推迟,那么也可能最终得到的value是个promise对象。(这是规范允许的,但NodeJS和blubird对promise规范的实现都对父promise的状态转换进行了推迟)

情景:在一个已经转换了状态的promise中再次调用这个promise的then方法

此时也会走then中的self.status === FULFILLED/REJECTED 的分支,再次证明需要在then中添加这两个分支并用上settimeout

p1.then((value)=>{ //执行此回调时p1状态已经改变p1.then(...);
});
复制代码

x instanceof Promise 和 typeof x=function... 递归的区别

instance分支下的递归 因为存在对promise状态的判断,当resolve()没有对value进行判断时,instance分支下的结果value最终可能为promise对象,而x.then分支下因为没有对promise状态进行判断,故不会出现value为promise对象的情况。

其余Promise方法的实现

Promise.prototype.catch

此方法实现灰常简单,只需在最后一个then绑定完回调后再绑定一个错误的回调即可

promise.prototype.catch = function(onRejected){this.then(null,onRejected);
}
复制代码

Promise.all

此方法传入一组promise实例再返回一个最终的promise实例,当所有promise都转为fulfilled时返回的最终的promise实例将会转换为fulfilled,此时这个promise的值为传入的promise的值的集合。而如果传入的那组promise中有一个rejected,返回的promise就会rejected。

Promise.all = function(promises){return new Promise((resolve,reject)=>{let result = [],count = 0;function done(i,data){result[i] = data;if(++count===promises.length){resolve(result);}}for(let i=0;i<promises.length;++i){promises[i].then((value)=>{done(i,value);},(reason)=>{reject(reason);});}});
}
复制代码

Promise.race

也是传入一组promise返回一个promise,哪个promise先转换状态,就返回这个promise的结果

Promise.race = function(promises){return new Promise((resolve,reject)=>{for(let i=0;i<promises.length;++){promises[i].then(resolve,reject);}});
}
复制代码

Promise.promisify

将一个异步函数promise化,使其可以then,可以链式书写

Promise.promisify = function(fn){return function(...args){return new Promise((resolve,reject)=>{fn.apply(null,[...args,function(err,data){err?reject(err):resolve(data);}]);});}
}
复制代码

Promise.promisifyAll

将一个对象下的所有方法都promisify化

Promise.promisifyAll = function(obj){for(var attr in obj){if(obj.hasOwnProperty(key)&&typeof obj[attr]==='function'){obj[attr+'Async'] = Promise.promisify(obj[attr]);}}
}
复制代码

测试

要对实现的Promise进行测试,除了实现t规范要求then方法和catch方法外还需要先在你的promise下添加一个方法

Promise.deferred = Promise.defer = function(){let defer = {};defer.promise = new Promise(function(resolve,reject){defer.resolve = resolve;defer.reject = reject;});return defer;
}
复制代码

然后按下述进行测试

npm i -g promises-aplus-tests
promises-aplus-tests yourFileName.js
复制代码

实现代码【终板】

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';function Promise(executor) {let self = this; //缓存下self.value = undefined; //用来存放value和reason,因为promise只会处于一种状态故可只用一个变量来表示。self.status = PENDING; //将初始状态设置为pendingself.onFulfilledCallbacks = []; //用来存放所有成功的回调函数self.onRejectedCallbacks = []; //用来存放所有失败的回调函数try {executor(resolve, reject); //调用执行函数,将resolve和reject方法作为参数传入} catch (e) {reject(e); //若执行函数中存在异常直接用抛出的值来拒绝promise}function resolve(value) {if (value instanceof Promise) { //和resolvePromise有点联系的是 当then return的promise中又resolve了一个promise会先走这,会将resolve里的promise的值赋给调用resolve的promise(说法欠妥,意会即可)return value.then(resolve, reject); //这意味着如果promise1 resolve中是一个promise2,那么promise1状态的改变时间会被推迟,直到promise2状态改变调用promise2的回调时,promise1状态才会改变才会触发promise1的回调}setTimeout(function () {if (self.status === PENDING) {self.status = FULFILLED;self.value = value;self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.2. //2.2.6.}})}function reject(reason) {setTimeout(function () {if (self.status === PENDING) {self.status = REJECTED;self.value = reason;self.onRejectedCallbacks.forEach(cb => cb(self.value)); //2.2.3. //2.2.6.}})}
}Promise.prototype.then = function (onFulfilled, onRejected) { //2.2.1.//2.2.7.3-2.2.7.4 //2.2.5.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};let self = this,promise2; //2.2.7.0 //声明要返回的promise2if (self.status === PENDING) {//2.2.7.return promise2 = new Promise(function (resolve, reject) {//存储then方法绑定的回调函数 //2.2.6.self.onFulfilledCallbacks.push((value) => {try {let x = onFulfilled(value);resolvePromise(promise2, x, resolve, reject); //2.2.7.1 //resolve/reject属于promise2 //若此方法执行说明promise1状态已经更改} catch (e) {reject(e); //2.2.7.2}});self.onRejectedCallbacks.push((reason) => {try {let x = onRejected(reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});});} else if (self.status === FULFILLED) {return promise2 = new Promise(function (resolve, reject) {setTimeout(function () {try {let x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})});} else {return promise2 = new Promise(function (resolve, reject) {setTimeout(function () {try {let x = onRejected(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})});}};function resolvePromise(promise2, x, resolve, reject) {if (x === promise2) { //2.3.1.return reject(new TypeError('禁止循环引用!'));}let called = false;//2.3.2.if (x instanceof Promise) {if (x.status === PENDING) { //2.3.2.1x.then((y) => {resolvePromise(promise2, y, resolve, reject); //因为此时的y,有可能也是一个promise //挂上一个钩子只要x状态转化为成功态就递归调用resolvePromise}, reject);} else { //此分支存在的意义在于若executor调用resolve/reject不是异步的且不在resolve/reject中设置setTimeout,意味着当new的时候就会返回一个带状态的promise就会走这里。x.then(resolve, reject); //2.3.2.2-2.3.2.3 //只要x状态改变,就以x的状态和值来改变promise2的状态和值 //这个值可能是一个promise,前提是在上面那种假设实现中 //如果不符合上面那种实现且不想像规范一样允许值可以为一个promise或则对象 可除去此分支}} else if (x != null && ((typeof x === 'function') || (typeof x === 'object'))) { //2.3.3.try {let then = x.then; //2.3.3.1if (typeof then === 'function') {//2.3.3.3.then.call(x, (y) => {if (called) return; //2.3.3.3.3.called = true;resolvePromise(promise2, y, resolve, reject); //在resolve中又包含promise的情况下,由于resolve中的 value.then存在,当前回调调用时,resolve中的promise状态一定已经改变,在状态已经改变的时候利用then绑定回调,会走then中的status==fulfilled或则rejected分支}, (reason) => {if (called) return;called = true;reject(reason);});} else {resolve(x); //2.3.3.4. //1.3}} catch (e) {if (called) return; //2.3.3.3.4.1.called = true;reject(e); //2.3.3.2. //2.3.3.3.4.2.}} else { //2.3.4.resolve(x);}
}Promise.deferred = Promise.defer = function () {let defer = {};defer.promise = new Promise(function (resolve, reject) {defer.resolve = resolve;defer.reject = reject;});return defer;
};Promise.prototype.catch = function (onRejected) {this.then(null, onRejected)
};Promise.resolve = function (value) {return new Promise((resolve, reject) => {resolve(value);})
};Promise.reject = function (reason) {return new Promise((resolve, reject) => {reject(reason);})
};Promise.all = function(promises){return new Promise((resolve,reject)=>{let result = [];let count = 0;function done(i,data){result[i] = data;if(++count === promises.length){resolve(result);}}for(let i=0;i<promises.length;++i){promises[i].then((value)=>{done(i,value);},reject);}})
};Promise.race = function(promises){return new Promise(function(resolve,reject){for(let i=0;i<promises.length;++i){promises[i].then(resolve,reject);}});
};Promise.promisify = function(fn){return function(...args){return new Promise((resolve,reject)=>{fn.apply(null,[...args,function(err,data){err?reject(err):resolve(data);}]);});}
};Promise.promisifyALL = function(obj){for(var key in obj){if(obj.hasOwnProperty(key)&&typeof obj[key]=='function'){obj[key+'Async'] = Promise.promisify(obj[key]);}}
};
module.exports = Promise;
复制代码

Promise深度学习---我のPromise/A+实现相关推荐

  1. 十二、Promise的学习笔记(Promise的基本使用、链式编程、all())

    一.认识Promise ES6中一个非常重要和好用的特性就是Promise 但是初次接触Promise会一脸懵逼,这TM是什么东西? 看看官方或者一些文章对它的介绍和用法,也是一头雾水. Promis ...

  2. ES6基础5(Promise)-学习笔记

    文章目录 ES6基础5(Promise)-学习笔记 Promise 三个状态 状态转换 手写Promise源码 同步异步概念 jquery中 串行并行 async-await 微任务 宏任务 ES6基 ...

  3. Promise相关学习

    仅代表个人学习 1.函数对象与实例对象 <script>function Person() { //首字母大写,这是一个构造函数}//给函数对象添加属性Person.age=18conso ...

  4. 【ES6】阮一峰ES6学习之Promise(一)

    Promise 一.含义 1. 概念 2. 特点 3. 基本用法 4. 为什么要用 Promise 1. 指定回调函数的方式更加灵活 2. 支持链式调用,可以解决回调地狱的问题 用Promise实现A ...

  5. ES6 --- Promise深入学习(二)Promise,then,catch,finally,及使用示例

    Promise 想象一下,你是一位顶尖歌手,粉丝没日没夜地询问你下首歌什么时候发. 为了从中解放,你承诺(promise)会在单曲发布的第一时间发给他们.你给了粉丝们一个列表.他们可以在上面填写他们的 ...

  6. 分析Promise,手写Promise,学习Promise,感受Promise

    整体思路分析: * 1.Promise一共有三种状态,成功fulfilled 失败rejected 等待pending  * pending => fulfilled 等待变成成功  * pen ...

  7. Github标星24k,127篇经典论文下载,这份深度学习论文阅读路线图不容错过

    作者  | Floodsung 翻译 | 黄海广 来源 | 机器学习初学者(ID:ai-start-com) [导读]如果你是深度学习领域的新手,那么你可能会遇到的第一个问题是"我应该从哪篇 ...

  8. AI:《DEEP LEARNING’S DIMINISHING RETURNS—深度学习的收益递减》翻译与解读

    AI:<DEEP LEARNING'S DIMINISHING RETURNS-深度学习的收益递减>翻译与解读 导读:深度学习的收益递减.麻省理工学院的 Neil Thompson 和他的 ...

  9. 【项目实战】vue-springboot-pytorch前后端结合pytorch深度学习 html打开本地摄像头 监控人脸和记录时间

    是一个项目的一个功能之一,调试了两小时,终于能够 javascript设置开始计和暂停计时 监控人脸 记录时间了 效果图: 离开页面之后回到页面会从0计时(不是关闭页面,而是页面失去焦点) 离开摄像头 ...

最新文章

  1. 分布式WebSocket架构
  2. 零基础学Python(第十章 循环嵌套)
  3. 广州电子厂房净化工程_简述设计电子车间净化工程的注意要点
  4. linux控制流程,Linux - Bash - 流程控制
  5. 基础练习 高精度加法(蓝桥杯 java)
  6. python interactive slider_python3----练习题(过滑块验证)
  7. 没有文件扩展“.vbs”的脚本引擎的解决方案
  8. 使用MHA对mysql主从架构中的主节点做高可用
  9. 太强了!这款轻量级中间件几行代码就搞定SpringBoot的分库分表问题
  10. 设置嵌入式系统开机自动启动程序
  11. 现代操作系统---1.操作系统的结构
  12. 信息管理系统项目前端界面设计
  13. 工具------Java反编译工具XJad
  14. 「AI」一文看懂“声纹识别VPR”
  15. 解决Win7的svchost进程占内存过大,计算机运行过慢的方法
  16. 【毕业设计】单片机 火灾智能报警系统 - 嵌入式 物联网
  17. docker使用阿里云的镜像加速器的地址
  18. Flex TLF框架
  19. 360公司2019校招笔试编程题合集答案——python版本
  20. Arcgis经纬线标注设置(英文、刻度显示)

热门文章

  1. 诡异的bug: tcsh陷入死循环
  2. ITSM为人服务,还是人为ITSM服务?
  3. php采集百度推荐词,php抓取百度快照、百度收录、百度热词程序代码_PHP教程
  4. 4月22日MySQL学习
  5. git clone错误 fatal: early EOF fatal: index-pack failed
  6. Excel,此文件中的某些文本格式可能已经更改,因为它已经超出最多允许的字体数。...
  7. Google Deepmind大神David Silver带你认识强化学习
  8. Facebook发布人工智能产品DeepText:能以人类智商
  9. iOS/OS X内存管理(一):基本概念与原理
  10. 互联网分布式微服务云平台规划分析--服务监控中心