- Promise就是一个类 在执行这个类的时候需要传递一个执行器进去,执行器会立即执行
- Promise中有三种状态:成功(fulfilled)、失败(rejected)和等待(pending),一旦状态确定就不能改,状态只能从等待变为成功或者变为失败
- resolve和reject函数是用来更改状态的
- then方法内部做的事情就是判断状态,如果状态是成功 调用成功的回调函数。then方法是被定义在原型对象中的
- then成功回调有一个参数 表示成功之后的值,失败回调参数表示失败的原因
- then方法可以被多次调用
- then方法是可以被链式调用的,后面then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
- then方法的参数是可选参数
const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class MyPromise {constructor (executor) {try {executor(this.resolve, this.reject)} catch (e) {this.reject(e)}}status = PENDING// 成功之后的值value = undefined// 失败之后的原因reason = undefined// 成功回调successCallback = []// 失败回调failCallback = []resolve = value => {// 如果状态不是等待 阻止程序向下执行if(this.status !== PENDING) returnthis.status = FULFILLEDthis.value = value// 判断成功回调是否存在 如果存在就调用while(this.successCallback.length){this.successCallback.shift()()}}reject = reason => {// 如果状态不是等待 阻止程序向下执行if(this.status !== PENDING) returnthis.status = REJECTEDthis.reason = reason// 判断失败回调是否存在 如果存在就调用while(this.failCallback.length){this.failCallback.shift()()}}then (successCallback, failCallback) {// 如果不传参数或者传递的不是函数 那就补充一个函数if(Object.prototype.toString.call(successCallback) !== "[object Function]"){successCallback = value => value}if(Object.prototype.toString.call(failCallback) !== "[object Function]"){failCallback = reason => { throw reason }}let promise2 = new MyPromise((resolve,reject) => {if(this.status === FULFILLED) {queueMicrotask(()=> {try{// 上一个then的成功回调返回值let x = successCallback(this.value)// 判断 x 的值是普通值还是promise对象// 如果是普通值,直接调用resolve// 如果是promise对象 查看promise对象返回的结果// 再根据promise对象返回的结果 决定调用resolve 还是调用rejectresolvePromise(promise2,x,resolve,reject)}catch (e) {reject(e)}})} else if(this.status === REJECTED) {queueMicrotask(()=> {try{// 上一个then的成功回调返回值let x = failCallback(this.reason)// 判断 x 的值是普通值还是promise对象// 如果是普通值,直接调用resolve// 如果是promise对象 查看promise对象返回的结果// 再根据promise对象返回的结果 决定调用resolve 还是调用rejectresolvePromise(promise2,x,resolve,reject)}catch (e) {reject(e)}})} else {// 等待// 将成功回调和失败回调存储起来this.successCallback.push(()=> {queueMicrotask(()=> {try{// 上一个then的成功回调返回值let x = successCallback(this.value)// 判断 x 的值是普通值还是promise对象// 如果是普通值,直接调用resolve// 如果是promise对象 查看promise对象返回的结果// 再根据promise对象返回的结果 决定调用resolve 还是调用rejectresolvePromise(promise2,x,resolve,reject)}catch (e) {reject(e)}})})this.failCallback.push(() => {queueMicrotask(()=> {try{// 上一个then的成功回调返回值let x = failCallback(this.reason)// 判断 x 的值是普通值还是promise对象// 如果是普通值,直接调用resolve// 如果是promise对象 查看promise对象返回的结果// 再根据promise对象返回的结果 决定调用resolve 还是调用rejectresolvePromise(promise2,x,resolve,reject)}catch (e) {reject(e)}})})}})return promise2}}function resolvePromise(promise2, x, resolve, reject){if(promise2 === x) {return reject(new TypeError(""))}if(x instanceof MyPromise) {// promise对象x.then(resolve, reject)} else {// 普通值resolve(x)}}
- 如果promise.then返回的是它本身返回的promise,就会出现循环调用promise的错误
var promise = new Promise((resolve, reject) => {resolve(100)})var p1 = promise.then(val => {console.log(val)return p1 // 会出现循环调用的情况})p1.then(() => {}, err => {console.log(err) // 系统的promise能识别循环调用的错误})
- Promise.all方法实现
- 接受一个数组,会按照数组中元素的顺序调用异步代码执行,得到的结果就是调用的顺序
- 返回一个promise,支持链式调用
- 数组中所有promise都是成功的,才会变为成功状态,只要有一个失败 就会变为失败状态
class MyPromise() {static all (array) {let result = []let index = 0return new MyPromise((resolve, reject) => {function addData(key, value) {result[key] = valueindex ++;if(index === array.length) {resolve(result)}}for(let i = 0; i < array.length; i++) {let current = array[i];if(current instanceof MyPromise) {// promise对象current.then(value => addData(i, value), error => reject(error))}else {// 普通值addData(i, array[i])}}})}}
- Promise.resolve方法实现
class MyPromise {static resolve (value) {if(value instanceof MyPromise) {// 参数是promisereturn value} else {// 不是promisereturn new MyPromise(resolve => resolve(value))}}}
- finally方法
不管成功还是失败都会执行
class MyPromise {finally(callback) {return this.then(value => {return MyPromise.resolve(callback()).then(() => value)}, error => {return MyPromise.resolve(callback()).then(() => error)})}}
- catch方法
class MyPromise {catch(failCallback) {return this.then(undefined, failCallback)}}
