Promise解决了什么问题
- Promise解决了回调天堂的问题,一层一层嵌套的代码十分不美观,它带来了两个问题,可读性问题和信赖问题
- 信赖问题,在传统的异步编程中,往往会呈现回调过早、回调过晚或者没有回调、回调次数过多等等一些问题
- Promise最大的益处是在异步执行的流程中,把执行代码和处理结果的代码清晰地拆散了,Promise 将回调嵌套改成了链式调用,减少了可读性和信赖问题
看一个最简略的Promise的应用
const p1 = new Promise((resolve, reject) => { resolve('success')})p1.then((res) => console.log('res'), err => console.log(err))// success
Promise外围
- promise就是一个类,在执行这个类的时候,须要传递一个执行器
executor()
,执行器会立刻执行 executor
承受两个参数,别离是 resolve 和 reject- promise中有三种状态,别离为 胜利
fulfilled
,失败rejected
, 期待pending
, - promise 只能从
pending
到rejected
, 或者从pending
到fulfilled
, - promise 的状态一旦确认,就不会再扭转
- then办法外部做的事件就是判断状态,如果状态是胜利,调用胜利的回调函数,如果状态是失败,调用失败的函数,then办法是被定义在原型对象上的
- promise 能够then屡次,
promise
的then 办法返回一个promise
- then 的参数
onFulfilled
和onRejected
是可选的 - then胜利回调有一个参数,示意
胜利
之后的值,then失败
回调有一个参数,示意失败后的起因
咱们能够写出Promise的大抵构造
const PENDING = 'pending'; // 期待const FULFILLED = 'fulfilled'; // 胜利const REJECTED = 'rejected'; // 失败class MyPromise { constructor (executor) { executor(this.resolve, this.reject) } // promise 状态 status = PENDING; // 胜利后的值 value = undefined; // 失败后的值 reason = undefined; resolve = () => { // 如果状态不是期待,阻止程序向下运行 if (this.status !== PENDING) return; // 将状态更改为胜利 this.status = FULFILLED; // 保留胜利之后的值 this.value = value; } reject = () => { // 如果状态不是期待,阻止程序向下运行 if (this.status !== PENDING) return; // 将状态更改为失败 this.status = REJECTED; // 保留失败后的起因 this.reason = reason; } then (successCallback, failCallback) { // 判断状态 if (this.status === FULFILLED) { successCallback(); } else if (this.status === REJECTED) { failCallback() } }}
测试一下
let p1 = new MyPromise((resolve, reject) => { resolve('胜利')})p1.then((value) => { console.log(value)}, reason => { console.log(reason)})// 胜利
Promise A+标准
Promise A+标准中文
Promise A+标准英文
依据标准咱们能够总结几条外围的规定,更多的标准咱们能够查看文档进行总结~
- 一个
Promise
的以后状态必须为以下三种状态中的一种:期待态(Pending)
、执行态(Fulfilled)
和回绝态(Rejected)
。 - Promise 的 then 办法承受两个参数
promise.then(onFulfiled, onRejected)
- then 办法能够被同一个 Promise 调用屡次
- then 办法必须返回一个 Promise 对象
上面咱们将一步步来实现Promise
Promise中退出异步逻辑
// 胜利回调successCallback = undefined;// 失败后的回调faliCallback = undefined;resolve = value => { // 判断胜利回调是否存在,如果存在 调用 this.successCallback && this.successCallback(this.value)}reject = reason => { // 判断失败回调是否存在,如果存在则调用 this.faliCallback && this.faliCallback(this.reason)}then (successCallback, faliCallback) { // 判断状态 if (this.status === FULFILLED) { successCallback(this.value) } else if (this.status === REJECTED) { faliCallback(this.reason); } else { // 期待 // 将期待回调和失败回调存储起来 this.successCallback = successCallback; this.faliCallback = faliCallback; }}
测试一下
let promise = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('success') }, 2000)})promise.then(value => { console.log(value)}, reason => { console.log(reason)})// success
实现then 办法屡次调用增加多个处理函数
- 分同步和异步状况解决
- 如果是同步间接调用回调函数,如果是异步,须要将回调函数存储起来
- 首先把胜利回调和失败回调的值变成数组
- 接着将胜利回调和失败回调应用push办法把胜利回调push进数组
- 当promise的状态变成胜利或者失败时,咱们须要顺次调用数组中的回调函数
- 当胜利回调的数组长度不等于0,就有回调函数,while 循环从前往后执行调用shift()办法,每执行一个删除一个,直到数组长度为0
successCallback = [];failCallback = [];// 将原来代码批改为// this.successCallback && this.successCallback(this.value);while (this.successCallback.length) this.successCallback.shift()(this.value);// this.faliCallback && this.faliCallback(this.reason);while (this.faliCallback.length) this.faliCallback.shift()(this.reason);
测试一下
let promise = new MyPromise((resolve, reject) => { // resolve('大白菜~~') // reject('失败') setTimeout(() => { resolve('大白菜~') }, 2000)})promise.then(value => { console.log(value)}, reason => { console.log(reason)})// 大白菜
实现then办法链式调用
Promise
的then
办法是能够链式调用的,前面的then
办法回调函数拿到的值实际上是拿到上一个then
办法回调函数的返回值- 实现
then
办法的链式调用,then
办法是Promise
对象上面的,如果要实现链式调用,那么每一个then
办法都应该返回一个Promise
对象
留神
- 在链式调用
then
办法的时候,回调函数能够返回一个一般值,和一个promise
对象 - 如果返回的是一般值,咱们能够间接调用
resolve(x)
把这个一般值传递给下一个promise
对象 - 如果是
promise
对象的话,咱们须要查看返回的promise
对象状态,如果状态是胜利的,咱们须要调用resolve
办法,把胜利的状态传递给它,
如果是失败的,须要把reject
传递给下一个promise
对象
// 革新then办法then (successCallback, faliCallback) { let promise2 = new myPromise((resolve, reject) => { // 判断状态 if (this.status === FULFILLED) { let x = successCallback(this.value); // 判断x的是是一般值还是promise对象 // 如果是一般值, 间接调用resolve // 如是是promise对象 查看promise对象返回的后果 // 在依据promise对象返回的后果 决定调用resovle还是reject resolvePromise(x, resolve, reject) // resolve(x) } else if (this.status === REJECTED) { faliCallback(this.reason); } else { // 期待 // 将期待回调和失败回调存储起来 this.successCallback.push(successCallback); this.faliCallback.push(faliCallback); } }); return promise2;}// 定义resolvePromise办法function resolvePromise(x, resolve, reject) { if (x instanceof myPromise) { // promise对象 x.then(resolve, reject); } else { // 一般值 }}// 测试一下let promise = new MyPromise((resolve, reject) => { resolve('大白菜~~') // reject('失败') // setTimeout(() => { // resolve('大白菜~') // }, 2000)})function other () { return new MyPromise((resolve, reject) => { resolve('other'); })}promise.then(value => { console.log(value); return other();}).then(value => { console.log(value)})// 大白菜// other
Promise then办法链式调用辨认Promise对象主动返回
当链式调用Promise
对象上面的then
办法的时候, 在then
办法回调函数中能够返回Promise
对象,但咱们须要思考另外一种状况,在then
办法回调函数中不能返回以后这个then
办法他所返回的Promise
对象, 如果返回了then
办法返回的Promise
对象,就会产生循环调用。
示例
let promise = new Promise((resolve, reject) => { resolve('大白菜')})let p1 = promise.then((value) => { console.log(value) return p1})// 报错// TypeError: Chaining cycle detected for promise #<Promise>
解决
- 在
then
办法中返回的Promise
对象就是promise 2 - 那么胜利的回调 返回的
Promise
对象就是 x - 判断
peomise2
与x
是否相等, - 相等就是本人返回了本人, 须要将状态放到
reject
革新代码
// 将then办法外面革新成异步代码退出setTimeout()setTimeout(() => { // 执行胜利调用胜利回调函数,拿到返回值 let x = successCallback(this.value); resolvePromise(promise2, x, resolve, reject)}, 0)// 革新resolvePromise办法function resolvePromise (promise2, x, resolve, reject) { // 判断是否相等 if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) } if (x instanceof MyPromise) { // promise 对象 x.then(resolve, reject) } else { // 一般值 resolve(x) }}
测试一下
let promise = new MyPromise((resolve, reject) => { resolve('大白菜')})let p1 = promise.then((value) => { console.log(value) return p1})p1.then((value) => { console.log(value)}, (err) => { console.log(err)})// 大白菜// Chaining cycle detected for promise #<Promise>
捕捉谬误及then链式调用其余状态
在执行结构器中退出try catch
constructor (executor) { try { executor(this.resolve, this.reject) } catch (e) { this.reject(e); }}// 测试一下let promise = new myPromise((resolve, reject) => { throw new Error('executor error')})promise.then(value => { console.log(value)}, reason => { console.log(reason.message)})// 胜利捕捉谬误 excutor error
then 回调函数捕捉谬误
// 在then办法的setTimeout 中增加try catchsetTimeout(() => { try { let x = successCallback(this.value); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) }}, 0)// 测试let promise = new MyPromise((resolve, reject) => { resolve('大白菜')})promise.then((value) => { console.log(value) throw new Error('then error')}, (err) => { console.log(err.message)}).then((value) => { console.log(value)}, reason => { console.log('~~~') console.log(reason.message)})// 大白菜// ~~~// then error
批改失败的中央
setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) }}, 0)// 测试一下let promise = new MyPromise((resolve, reject) => { reject('失败')})promise.then(value => { console.log(value)}, reason => { console.log(reason) return '大白菜~~';}).then(value => { console.log(value)})// 失败// 大白菜~~
当是异步的时候
将原来的代码改成
this.successCallback.push(successCallback);this.failCallback.push(failCallback);this.successCallback.push(() => { setTimeout(() => { try { let x = successCallback(this.value); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0)})this.failCallback.push(() => { setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0)})// 而后resolve和reject就不须要传值了while (this.successCallback.length) this.successCallback.shift()();while (this.failCallback.length) this.failCallback.shift()();
测试一下
let promise = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('success~~~~'); // reject('error~~~~') }, 2000)})promise.then((value) => { console.log(value) return '米糕';}, reason => { console.log(reason) return '大白菜';}).then((value) => { console.log(value);})// suceess~~~// 米糕
到这里Promise的外围性能就根本曾经实现啦~~~
将then办法的参数变成可选参数
- then办法有两个可选参数,一个胜利回调,一个失败回调
- 这两个参数都是可选参数,退出遇到一下状况
let promise = new Promise((resolve, reject) => { resolve(100)})promise .then() .then() .then(value => { cosole.log(value) })
- 在这种状况下, promise 会顺次往下传递
- 咱们须要在then办法中判断是否有参数,如果不存在就补一个参数,这样状态就能够顺次向后传递了
批改Promise的代码
在then办法咱们判断successCallback和failCallback是否存在
successCallback = successCallback ? successCallback : value => value;failCallback = failCallback ? failCallback : reason => { throw reason };
测试一下
let promise = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('success'); // reject('reject'); }, 2000)})promise.then().then().then(value => { console.log(value);}, reason => { console.log(reason);})// success// reject
Promise.all实现
- 接管一个数组作为参数填充,在数组中能够填入任意值,包含一般值和
Promise
对象,数组的程序肯定是失去后果的程序 Promise.all
特点在all
中的所有Promise
对象, 如果他的状态都是胜利的,那么all
办法就是胜利的,如果有一个是失败的, 那么就是失败的- 利用类 .上
all
所以all
是一个静态方法 Promise.all
是解决异步并发问题, 容许依照异步代码调用的程序失去异步代码执行的后果, 因为all
办法是静态方法,all
后面定义static
关键字, all 办法接管一个数组作为参数,all
办法的返回值也是一个Promise
对象, 在Promise
对象中通过循环 传递的数组,在循环的过程判断是一般值,还是Promise 对象, 进行不同的调用- 如果参数中有一个
Promise
失败,那么Promise.all
返回的Proise
对象失败
static all(array) { let result = [] let index = 0 return new MyPromise((resolve, reject) => { // 执行for 循环有异步操作,循环没有期待异步操作。 // 如果index 等于 array的length 就调用resolve function addData (key, value) { result[key] = value; index++ if (index === array.length) { resolve(result) } } // 须要判断是一般值, 还是Promise 对象 for (let i = 0; i < array.length; i++) { let current = array[i]; if (current instanceof MyPromise) { // promise 对象 current.then(value => addData(i, value), reason => reject(reason) ) } else { // 一般值 addData(i, array[i]) } } })}
测试一下
function p1() { return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('p1') }, 1000) })}function p2() { return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('p1') }, 1000) })}MyPromise.all(['a', 'b', p1(), p2(), 'c']).then(result => { console.log(result)})// [ 'a', 'b', 'p1', 'p1', 'c' ]
Promise.resolve 办法实现
Promise.resolve
的作用是将给定的值转换为Promise
对象, 也就是说Promise.resolve
的返回值就就是一个Promise对象,在返回的Promise
对象中会包裹给定的这个值- 在
resolve
的外部, 会创立一个Promise
对象,并把这个值包裹在Promise
对象中,而后把创立进去的Promise
对象最作为resolve
的返回值,正是因为这样,咱们能力前面进行链式调用then
办法, 通过then办法的胜利回调函数来拿到这个值,Promise.resolve
也能够接管一个Promise
对象, 在Promise.resolve
外部会判断给定的值是一般值还是Promise
对象,如果是Promise
对象的话,会一成不变把Promise
在作为Promise.resolve
的返回值,所以能力在后在调用then
办法,通过then办法胜利回调函数来拿到Promise
对象的返回值
static resolve(value) { if (value instanceof myPromise) return value; return new MyPromise(resolve => resolve(value))}
测试一下
function p1() { return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('p1') }, 1000) })}MyPromise.resolve('大白菜').then(value => console.log(value))MyPromise.resolve(p1()).then(value => console.log(value))// 大白菜// p1
Promise.reject()
static reject(reason) { return new MyPromise((resolve,reject) => reject(reason))}
Promise.finally办法实现
Promise.finally有两个特点
- 无论以后这个
Promise
对象最终的状态是胜利还是失败,finally
办法这个会回调函数始终都会执行一次 - 在
finally
的前面能够链式调用then
办法来拿到以后这个Promise
对象最终返回的后果
finally(callback) { return this.then(value => { callback(); return value }, reason => { callback(); throw reason })}
测试一下
function p1() { return new MyPromise((resolve, reject) => { resolve('p1 reject') // reject('p1 reject') })}function p2() { return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('p2') }, 2000) })}p1().finally(() => { console.log('finally'); // return p2();}).then(value => { console.log(value);}, reason => { console.log(reason);})// finally// p1 reject
- 在
finally
的回调函数中,其实能够在return
一个Promise
对象 - return p2前面的then须要期待setTimeout之后执行
- 借助
resolve
办法 - 如果
callback
返回的是一般值,转换Promise
对象, 期待Promise
对象执行实现,如果返回的是Promise
对象,还期待你执行实现,在返回value
优化下面的代码
finally(callback) { return this.then(value => { return MyPromise.resolve(callback()).then(() => value); }, reason => { return MyPromise.resolve(callback()).then(() => { throw reason },); })}
测试一下
function p1() { return new MyPromise((resolve, reject) => { setTimeout(() => { resolve('p1 resolve') }, 2000) })}function p2() { return new MyPromise((resolve, reject) => { resolve('p2 resolve') // reject('p2 reject') })}p2().finally(() => { console.log('finally'); return p1()}).then(value => { console.log(value);}, reason => { console.log(reason);})// finally // 期待2s后执行 输入p2 resolve
Promise.catch 办法实现
catch
办法的作用是用来解决以后这个Promise
对象最终状态为失败的状况的,就是说当咱们调用then办法时候,咱们能够不传递失败回调, 如果不传失败回调,那么失败回调就能够被catch捕捉,从而去执行传入到catch办法的回调函数- 只须要在catch办法外部去调用then办法就能够了
catch (failCallback) { return this.then(undefind, failCallback);}
测试一下
function p1() { return new MyPromise((resolve, reject) => { // resolve('大白菜~~') reject('error') })}p1() .then(value => console.log(value)) .catch(reason => console.log(reason))
Promise.race()
Promise.race
只返回第一个执行结束的Promise
的后果,无论后果是fullfilled
还是rejected
static race(promises) { return new MyPromise((resolve, reject) => { if (promises.length === 0) { return } else { for (let p of promises) { MyPromise.resolve(p).then(value => { resolve(value) }, reason => { reject(reason) }) } } })}
测试一下
const MyPromise = require('./myPromise');let promise1 = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('大白菜') }, 2000)});let promise2 = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('米糕') }, 1000)});MyPromise.race([promise1, promise2]).then((value) => { console.log(value);});// 米糕
残缺代码
const PENDING = 'pending'; // 期待const FULFILLED = 'fulfilled'; // 胜利const REJECTED = 'rejected'; // 失败class MyPromise { constructor (executor) { try { executor(this.resolve, this.reject) } catch (e) { this.reject(e); } } // promise 状态 status = PENDING; // 胜利后的值 value = undefined; // 失败后的值 reason = undefined; // 胜利回调 successCallback = []; // 失败后的回调 failCallback = []; resolve = value => { // 如果状态不是期待,阻止程序向下运行 if (this.status !== PENDING) return; // 将状态更改为胜利 this.status = FULFILLED; // 保留胜利之后的值 this.value = value; // 判断胜利回调是否存在,如果存在 调用 // this.successCallback && this.successCallback(this.value); while (this.successCallback.length) this.successCallback.shift()(); } reject = reason => { // 如果状态不是期待,阻止程序向下运行 if (this.status !== PENDING) return; // 将状态更改为失败 this.status = REJECTED; // 保留失败后的起因 this.reason = reason; // 判断失败回调是否存在,如果存在则调用 // this.faliCallback && this.faliCallback(this.reason); while (this.failCallback.length) this.failCallback.shift()(); } then (successCallback, failCallback) { // 依据标准,如果then的参数不是function,则咱们须要疏忽它, 让链式调用持续往下执行 successCallback = typeof successCallback === 'function' ? successCallback : value => value; failCallback = typeof failCallback === 'function' ? failCallback : reason => { throw reason }; let promise2 = new MyPromise((resolve, reject) => { // 判断状态 if (this.status === FULFILLED) { setTimeout(() => { try { let x = successCallback(this.value); // 判断x的是是一般值还是promise对象 // 如果是一般值, 间接调用resolve // 如是是promise对象 查看promise对象返回的后果 // 在依据promise对象返回的后果 决定调用resovle还是reject resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } else if (this.status === REJECTED) { setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } else { // 期待 // 将期待回调和失败回调存储起来 this.successCallback.push(() => { setTimeout(() => { try { let x = successCallback(this.value); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) // 将胜利回调推入 this.failCallback.push(() => { setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) // 将失败回调推入 } }); return promise2; } static all(array) { let result = [] let index = 0 return new MyPromise((resolve, reject) => { // 执行for 循环有异步操作,循环没有期待异步操作。 // 如果index 等于 array的length 就调用resolve function addData (key, value) { result[key] = value; index++; // 保障all的每一项都执行完了 if (index === array.length) { resolve(result); } } // 须要判断是一般值, 还是Promise 对象 for (let i = 0; i < array.length; i++) { let current = array[i]; if (current instanceof MyPromise) { // promise 对象 current.then(value => addData(i, value), reason => reject(reason)); } else { // 一般值 addData(i, array[i]) } } }) } static resolve(value) { if (value instanceof MyPromise) return value; return new MyPromise(resolve => resolve(value)) } static reject(reason) { return new MyPromise((resolve,reject) => reject(reason)) } static race(promises) { return new MyPromise((resolve, reject) => { if (promises.length === 0) { return } else { for (let p of promises) { MyPromise.resolve(p).then(value => { resolve(value) }, reason => { reject(reason) }) } } }) } // finally链式调用返回Promise finally(callback) { return this.then(value => { return MyPromise.resolve(callback()).then(() => value); }, reason => { return MyPromise.resolve(callback()).then(() => { throw reason },); }) } catch (failCallback) { return this.then(undefined, failCallback); }}function resolvePromise (promise2, x, resolve, reject) { // 判断是否相等 if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) } if (x instanceof MyPromise) { // promise 对象 x.then(resolve, reject) } else { // 一般值 resolve(x) }}module.exports = MyPromise;
总结
以上就是对Promise的实现的整个过程,咱们首先从一个简略Promise的应用实例开始,对Promise的外围进行了剖析,依据剖析咱们实现了大抵的一个构造,而后依据Promise A+标准一步一步的进行填充代码。次要实现了
- Promise 异步逻辑
- 实现then 办法屡次调用增加多个处理函数
- Promise.then()办法链式调用
- Promise.then()参数为可选参数
- Promise.all()
- Promise.resolve()
- Peomise.reject()
- Promise.finally()
- Promise.catch()
- Promise.rece()
感激大家
最初感谢您花贵重的工夫浏览这篇内容,如果你感觉这篇内容对你有帮忙的话,就给本文点个赞吧,
(感激大家的激励与反对????????????)
参考
Promise A+标准
Promise源码实现
9k字 | Promise/async/Generator实现原理解析