异步编程怎么搞,Promise知多少?

116 阅读15分钟

深入了解Promise,掌握Promise基础使用、链式调用、静态方法等;通过手写Promise深入理解其核心机制

Promise简介

Promise 是异步编程的一种解决方案: 从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果

promise有三种状态:pending(等待态),fulfiled(成功态),rejected(失败态)状态一旦改变,就不会再变。创造promise实例后,它会立即执行。

promise解决的问题:

  • 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
  • promise可以解决异步的问题,但不能说promise是异步的(注意promise本身是同步的

Promise的基本使用

由下面可知:thencatchfinally都是Promise的实例方法,放在Promise.prototype上。

console.log(Object.getOwnPropertyDescriptors(Promise.prototype));
// {
//     constructor: {
//         value: [Function: Promise],
//         writable: true,
//         enumerable: false,
//         configurable: true
//     },
//     then: {
//         value: [Function: then],
//         writable: true,
//         enumerable: false,
//         configurable: true
//     },
//     catch: {
//         value: [Function: catch],
//         writable: true,
//         enumerable: false,
//         configurable: true
//     },
//     finally: {
//         value: [Function: finally],
//         writable: true,
//         enumerable: false,
//         configurable: true
//     },
//     [Symbol(Symbol.toStringTag)]: {
//         value: 'Promise',
//         writable: false,
//         enumerable: false,
//         configurable: true
//     }
// }

创建

使用 new Promise 构造函数可以创建一个 Promise 对象,并提供一个执行器函数(executor function),该函数有两个参数,通常命名为 resolvereject

const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 操作成功 */) {
    resolve('Promise is resolved successfully.');
  } else {
    reject('Promise is rejected with an error.');
  }
});

使用

then() 和 catch() 方法

  • .then(onFulfilled, onRejected)当 Promise 被成功解决时,调用 onFulfilled 回调;如果被拒绝,则调用 onRejected 回调。
  • .catch(onRejected):用于指定当 Promise 被拒绝时的回调函数
myPromise
  .then((value) => {
    console.log(value); // "Promise is resolved successfully."
  })
  .catch((error) => {
    console.error(error);
  });

或者:

myPromise
  .then((value) => {
    console.log(value); // "Promise is resolved successfully."
  }, catch((error) => {
    console.error(error);
  }))

finally() 方法

.finally(onFinally)无论 Promise 对象是被解决还是被拒绝,都会执行的回调函数。

myPromise
  .then((value) => console.log(value))
  .catch((error) => console.error(error))
  .finally(() => console.log('Promise is settled.'));

链式调用

Promise then() catch() 方法返回的都是一个新的 Promise 对象,这允许进行链式调用。

myPromise
  .then((firstResult) => {
    // 处理第一个异步操作的结果
    return anotherAsyncOperation();
  })
  .then((secondResult) => {
    // 处理第二个异步操作的结果
  })
  .catch((error) => {
    // 处理错误
  });

Promise状态

三种状态

一个 Promise 对象有三种状态:

  1. Pending(进行中) :初始状态,既不是成功,也不是失败状态。
  2. Fulfilled(已成功) :操作成功完成。
  3. Rejected(已失败) :操作失败。

Promise 的状态转移是单向的,只能从 PendingFulfilledPendingRejected,不能逆向转换,也不能从成功或失败状态转回进行中状态。

resolve()的参数决定promise状态

当 Promise 的 resolve 方法被调用时,其参数决定了 Promise 的状态:

  1. 如果参数是一个普通值或普通对象(非 Promise 对象) ,则 Promise 对象变为 fulfilled(已解决)状态,并且该值成为 Promise 的结果值。
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') // 传入的是一个普通值,则promise的状态会变为fulfilled
    }, 1000)
})

promise.then((data) => {console.log(data);}) // success
  1. 如果参数是一个 Promise 对象,则原始 Promise 对象的状态取决于被解析的 Promise 对象的状态

    • 如果被解析的 Promise 对象是 pending 状态,则原始 Promise 对象也保持 pending 状态,直到被解析的 Promise 对象状态改变。
    • 如果被解析的 Promise 对象是 fulfilled(已解决)状态,则原始 Promise 对象也变为 fulfilled 状态,并且其值为被解析的 Promise 对象的值。
    • 如果被解析的 Promise 对象是 rejected(已拒绝)状态,则原始 Promise 对象也变为 rejected 状态,并且其原因为被解析的 Promise 对象的原因。
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(new Promise((resolve, reject) =>{
            reject("现在状态是rejected") 
// 传入的是一个promise,此时的状态就会由resolve参数promise的状态决定,也就是rejected
        })) 
    }, 1000)
})

promise.then((data) => {console.log(data);})
       .catch((error) => {console.log(error);}) // 现在状态是rejected
  1. 如果参数是一个 thenable 对象(具有 then 方法的对象) ,其行为类似于一个 Promise 对象

    • 如果 thenable 对象的 then 方法被成功调用,则原始 Promise 对象也变为 fulfilled 状态,并且其值为 thenable 对象 resolve 后的值。
    • 如果 thenable 对象的 then 方法抛出异常,则原始 Promise 对象也变为 rejected 状态,并且其原因为 thenable 对象抛出的异常。
const thenableObj = {
    then(resolve, reject){
        resolve('我是thenable对象')
    }
}
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(thenableObj) // 传入的是一个thenable对象,状态就由thenable对象决定
    }, 1000)
})

promise.then((data) => {console.log(data);})
       .catch((error) => {console.log(error);}) // 我是thenable对象

then方法

多次调用then方法

一个promise可以多次调用then方法。

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') 
    }, 1000)   
})

// 多次调用then方法
promise.then((data) => {console.log(data);}) 
promise.then((data) => {console.log(data);}) 
promise.then((data) => {console.log(data);}) 
// 输出:
// success
// success
// success

then方法的返回值(链式调用)

resolve()的参数决定promise状态类似。then方法的返回值都会作为执行完then方法后新产生的promise的resolve的参数。 默认不写的话就等同于return undefined会把undefined作为resolve的参数。

  1. 返回一个普通值(数值/字符串/普通对象/undefined),那么这个返回的普通值将会作为新promiseresolve的参数
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') 
    }, 1000)   
})

promise.then((data1) => {
    console.log(data1)
    return data1 // 会将data1传递给新Promise的resolve
})
.then(data2 => {console.log(data2)})
// 输出:
// success
// success
  1. 返回一个promise,则新 Promise 的状态取决于被返回的 Promise 的状态。
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') 
    }, 1000)   
})

promise.then((data1) => {
    console.log(data1)
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            reject('failure')
        }, 1000)
    }) // 新Promise的状态会由这个new Promise的状态决定
})
.then(data2 => {console.log(data2)})
.catch((error) => {console.log(error)})
// 输出:
// success
// failure
  1. 返回一个 thenable 对象(具有 then 方法的对象),其行为类似于一个 Promise 对象
    • 如果 thenable 对象的 then 方法被成功调用,则原始 Promise 对象也变为 fulfilled 状态,并且其值为 thenable 对象 resolve 后的值。
    • 如果 thenable 对象的 then 方法抛出异常,则原始 Promise 对象也变为 rejected 状态,并且其原因为 thenable 对象抛出的异常。
const thenableObj = {
    then(resolve, reject){
        resolve('我是thenable对象')
    }
}

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') 
    }, 1000)   
})

promise.then((data1) => {
    console.log(data1)
    return thenableObj // 新Promise的状态会由这个thenable对象决定
})
.then(data2 => {console.log(data2)})
.catch((error) => {console.log(error)})
// 输出:
// success
// 我是thenable对象

catch方法

catch方法不仅可以捕获reject,也可以捕获throw new Error()

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') 
    }, 1000)
})

// Promise A+的写法:
promise.then(success => console.log(success), error => console.log(error))
// ES6的写法(链式):
promise.then(success => console.log(success)).catch(error => console.log(error))
  1. 不能分开分别调用then() catch() ,要么写成Promise A+的形式,要么写成ES6的形式。但是和then一样,catch也可以进行多次调用。
  2. catch() 按照顺序的优先级来捕获rejectthrow new Error()
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success') 
    }, 1000)
})

promise.then(success => {
    console.log(success)
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('new Promise error')
        }, 1000)
    })
})
.catch(error => console.log(error))

// 输出:
// success
// new Promise error

上面代码中,最开始的promiseresolve,不会捕获异常,而then返回的是一个promise,其reject,故catch会捕获到reject('new Promise error')

但下面这个例子中,最开始的promisereject,会被catch捕获到,那么后面then返回的promise,虽然是reject,但是不会被捕获到。

catch就是按照这样的顺序优先级来捕获的。

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('failure') // 一开始就reject,则会捕获这的reject
    }, 1000)
})

promise.then(success => {
    console.log(success)
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('new Promise error')
        }, 1000)
    })
})
.catch(error => console.log(error))
// 输出:
// failure
  1. catchthen一样,也可以有返回值,而且和then一样,返回的值会被传到new Promiseresolve

finally方法

  • 不管resolve还是reject最终都会执行的。
  • 回调函数没有参数。
  • finally也可以多次调用。

Promise的类方法(静态方法)

Promise.resolve()Promise.reject()方法

用于返回成Promise。

Promise.resolve()

还是由resolve()的参数决定promise状态

// 传普通值(普通对象)
const promise1 = Promise.resolve({a:1, b:2})
promise1.then(data1 => console.log(data1))
// 相当于:
const promise1 = new Promise((resolve, reject) => {
    resolve({a:1, b:2})
})
promise1.then(data1 => console.log(data1))



// 传一个promise
const promise2 = Promise.resolve(new Promise((resolve, reject) => resolve("hello, I'm a promise")))
promise2.then(data2 => console.log(data2))
// 相当于:
const promise2 = new Promise((resolve, reject) => {
    resolve(new Promise((resolve, reject) => resolve("hello, I'm a promise")))
})
promise2.then(data2 => console.log(data2))



// 传一个thenable对象
const thenableObj = {
    then(resolve, reject){
        resolve('我是thenable对象')
    }
}
const promise3 = Promise.resolve(thenableObj)
promise3.then(data3 => console.log(data3))
// 相当于:
const promise3 = new Promise((resolve, reject) => {
    resolve(thenableObj)
})
promise3.then(data3 => console.log(data3))

考考你,下面这段代码会输出什么?

Promise.resolve()
    .then(() => {
        console.log(0);
        return Promise.resolve(4);
    })
    .then((res) => {
        console.log(res)
    })

Promise.resolve()
    .then(() => {
        console.log(1);
    })
    .then(() => {
        console.log(2);
    })
    .then(() => {
        console.log(3);
    })
    .then(() => {
        console.log(5);
    })
    .then(() => {
        console.log(6);
    })
// 输出:0 1 2 3 4 5 6

分析:

  • 一个promiseresolve后,状态变成Fulfilled ,会把then() 里面的回调函数放到微队列里面执行;相对应的, reject后,状态变成Rejected ,会把catch() 里面的回调函数放到微队列里面执行。
  • then() 方法会返回一个promise。
  • 如果promise1resolve(普通值a) 后在then() 中return了一个新的promise(promise2),(V8源码中)那么就会把promise2.then((普通值a)=> promise1的then()返回的promise .resolve(普通值a)) 这一段代码放到微队列里面等待执行。

Promise.reject()

注意:reject可不会和resolve一样由参数来决定promise状态,不管传的参数是什么都只会执行catch

const thenableObj = {
    then(resolve, reject){
        resolve('我是thenable对象')
    }
}
const promise = Promise.reject(thenableObj)
promise.then(data => console.log(data))
       .catch((error) => {console.log(error)})
// 输出:{ then: [Function: then] }

Promise.all()Promise.allSettled()

Promise.all()

  • 当所有的promise都resolve后会以数组的形式返回所有resolve的结果,顺序是按照写在Promise.all() 里面的顺序,而不是按照每个promise响应的顺序。
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise1')
    }, 1000)
})

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise2')
    }, 2000)
})

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise3')
    }, 3000)
})

Promise.all([promise3, promise2, promise1]).then(res => {
    console.log(res);
})
// 输出:[ '我是promise3', '我是promise2', '我是promise1' ]
  • 只要这些promise中有一个reject了,那么就会直接catchreject的那个promise( 只会catch出最先reject的那个,一遇到reject就会立即catch)。
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise1')
    }, 1000)
})

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('我是promise2,reject了')
    }, 2000)
})

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise3')
    }, 3000)
})

Promise.all([promise3, promise2, promise1]).then(res => {
    console.log(res);
})
.catch(err => console.log(err));
// 输出:我是promise2,reject了

Promise.allSettled()

Promise.allSettled() 则会等所有promise都响应完最后直接输出一个 对象数组,里面包含每个promise的status和value/reason 顺序还是按照写在Promise.allSettled() 里面的顺序。

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise1')
    }, 1000)
})

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('我是promise2,reject了')
    }, 2000)
})

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise3')
    }, 3000)
})

Promise.allSettled([promise3, promise2, promise1]).then(res => {
    console.log(res);
})
.catch(err => console.log(err));
// 输出:
// [
//     { status: 'fulfilled', value: '我是promise3' },
//     { status: 'rejected', reason: '我是promise2,reject了' },
//     { status: 'fulfilled', value: '我是promise1' }
// ]

Promise.race()Promise.any()

Promise.race()

会调用第一个响应完的promise的then() catch()

  • 只要有一个Promise变成fulfilled状态,那么就结束,执行相应的then()
  • 只要有一个Promise变成rejected状态,那么就结束,执行相应的catch()
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise1')
    }, 1000)
})

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('我是promise2,reject了')
    }, 500)
})

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是promise3')
    }, 3000)
})

Promise.race([promise3, promise2, promise1]).then(res => {
    console.log(res);
})
.catch(err => console.log(err));
// 输出:我是promise2,reject了

Promise.any()

总是调用第一个resolve的promise的then()

  • Promise.any() 方法会等到一个fulfilled状态,才会决定新Promise的状态
  • 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态。
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('我是promise1,reject了')
    }, 1000)
})

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('我是promise2,reject了')
    }, 500)
})

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('我是promise3,reject了')
    }, 3000)
})

Promise.any([promise3, promise2, promise1]).then(res => {
    console.log(res);
})
.catch(err => console.error(err));
// 输出:
// [AggregateError: All promises were rejected] {
//     [errors]: [ '我是promise3,reject了', '我是promise2,reject了', '我是promise1,reject了' ]
//   }

Promise A+ 规范与ES6的promise

  • ES6(ECMAScript 2015)中的 Promise 是语言规范的一部分,并且现代浏览器和 JavaScript 运行环境都原生支持它。
  • ES6 的 Promise 是 JavaScript 异步编程的一个基础构件,它提供了一种更合理、更强大的异步编程模型。而 Promise A+ 规范是 Promise 的行为标准,确保了不同 JavaScript 环境中 Promise 的一致性和可预测性。
  • 在实际开发中,你通常不需要自己实现 Promise,而是直接使用 ES6 提供的 Promise 对象,或者使用库和框架提供的符合 Promise A+ 规范的 Promise 实现。

ES6 Promise 的基本用法

ES6 中的 Promise是一个构造函数,是对Promise A+ 规范的实现。注意:构造函数本身不是Promise,而是其创建的对象是Promise。ES6 中的 Promise还增加了catch()finally()Promise.all()Promise.allSettled()Promise.race()Promise.any()

创建 Promise

const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  const condition = true; // 假设这是异步操作的结果
  if (condition) {
    resolve('Promise is resolved successfully.');
  } else {
    reject('Promise is rejected with an error.');
  }
});

使用 Promise

myPromise
  .then((value) => {
    console.log(value); // 如果 promise 被成功解决,这里会打印 value
  })
  .catch((error) => {
    console.error(error); // 如果 promise 被拒绝,这里会打印 error
  });

Promise A+ 规范

Promise A+Promise 的一个规范,早于ES6,它定义了 Promise 的行为和接口,它的出现是为了解决回调地狱的问题。ES6 中的 Promise 实现遵循了这个规范。Promise A+ 规范确保了不同 JavaScript 环境中 Promise 的一致性。

Promise A+ 规范的关键点

  1. 状态Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。
  2. thenable 对象:遵循 Promise A+ 规范的 Promise 对象被称为 thenable 对象,因为它们拥有 then 方法。
  3. 链式调用Promisethen 方法返回一个新的 Promise 对象,这允许进行链式调用。
  4. 错误处理:如果在 .then().catch() 方法中抛出错误,那么这个错误会被下一个 .catch() 方法捕获。
  5. 回调函数Promise 的构造函数接受的执行器函数(executor function)中,resolve 用于解决 Promisereject 用于拒绝 Promise
  6. 惰性执行Promise 中的异步操作是惰性执行的,即直到 Promise.then().catch() 方法被调用时才开始执行。

Promise 与 Promise A+ 的关系

  • Promise A+ 是规范:它定义了 Promise 应该如何工作,包括它的接口和行为。
  • ES6 Promise 是实现:ES6 中的 Promise 是对 Promise A+ 规范的一个具体实现。
  • 兼容性:遵循 Promise A+ 规范的任何 Promise 实现都应该与遵循相同规范的其他 Promise 实现兼容。

手写promise

手写Promise的工具函数

  • catch:
Promise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected)
}

catch 方法(Promise A+规范里面没有catch())实际上是通过调用 then 方法来实现的。具体地,它传递了 null 作为第一个参数(表示对于解决的情况不做处理),并将传入的 onRejected 回调函数作为第二个参数(用于处理拒绝的情况)。因此,当 Promise 被拒绝时,onRejected 回调函数将被调用,而对于解决的情况,则不做处理。


  • finally:
finally(onFinally){
    return this.then(data =>{
        onFinally()
        // this的promise是成功的,那么返回的promise也是成功的
        return data
    }), err => {
        onFinally()
        // this的promise是失败的,那么返回的promise也是失败的
        throw err
    }
}

  • resolve:
function isPromiseLike(obj){
    // 满足A+规范的对象:有then方法的对象
    return obj && obj.then === 'function'
}

Promise.resolve = function(value){
    // 如果value是一个Promise对象,直接返回
    if(value instanceof Promise) return value
    // 如果value是一个thenable对象,返回一个新的Promise对象,并且将value的状态传递给新的Promise对象
    if(isPromiseLike(value)){
        return new Promise((resolve, reject) => {value.then(resolve, reject)})
    }
    // 如果value是一个普通值,返回一个新的Promise对象,状态为fulfilled
    return new Promise((resolve, reject) => {resolve(value)})
}

  • reject:
// Promise.reject(reason)返回一个状态为rejected的Promise对象
Promise.reject = function(reason){
    return new Promise((resolve, reject) => {reject(reason)})
}

手写Promise(完整版)

// 用常量表示状态,防止硬编码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    // 用#表示私有属性
    // 定义状态state和传的值result
    #state = PENDING
    #result = undefined
    // 定义回调函数(then)数组
    #handlers = []

    // 定义改变状态的方法
    #changeState(state, result){
        if(this.#state !== PENDING) return // Promise状态只能改变一次
        this.#state = state
        this.#result = result
        // 状态改变后才执行,防止异步
        this.#run()
    }
    // 判断是否是Promise对象
    #isPromiseLike(value){
        // 判断是否是对象并且有then方法
        return value && typeof value.then === 'function'
    }
    // 将函数放到微任务队列中执行
    #runMicroTask(func){
        // 分环境:
        // node环境
        if(typeof process === 'object' && typeof process.nextTick === 'function'){
            process.nextTick(func)
        } else if(typeof MutationObserver === 'function'){
            // 浏览器环墧:通过监听文本节点变化将函数放到微任务队列中
            const observer = new MutationObserver(func)
            const textNode = document.createTextNode('')
            observer.observe(textNode, {characterData: true})
            textNode.data = 'test'
        } else {
            // 其他环境:通过setTimeout将函数放到微任务队列中
            setTimeout(func, 0);
        }
    }
    // 执行回调函数(then)
    // 状态确定后执行callback
    #runOne(callback, resolve, reject){
        this.#runMicroTask(() => {
            if(typeof callback !== 'function'){
                // 如果callback不是函数,根据状态执行resolve或reject
                const settled = this.#state === FULFILLED ? resolve : reject
                settled(this.#result)
                return
            }
            // 如果callback是函数,执行callback
            // 同时也要try catch,callback执行出错时执行reject
            try{
                const data = callback(this.#result)
                // 如果callback返回的是Promise对象,执行then方法
                if(this.#isPromiseLike(data)){
                    data.then(resolve, reject)
                } else {
                    resolve(data)
                }
            } catch (err) {
                reject(err)
            }
        })
    }
    // 执行回调函数(then)数组
    #run(){
        if(this.#state === PENDING) return
        // console.log(this.#handlers);
        while(this.#handlers.length){
            // 每从handlers中取出一个handler,就解构出onFulfilled, onRejected, resolve, reject
            const {onFulfilled, onRejected, resolve, reject} = this.#handlers.shift()
            if(this.#state === FULFILLED){
                this.#runOne(onFulfilled, resolve, reject)
            } else if(this.#state === REJECTED){
                this.#runOne(onRejected, resolve, reject)
            }
        }
    }
    // 构造函数,传入执行器executor
    constructor(executor) {
        // 在构造器内部定义resolve和reject函数,防止this指向问题(绑定this)
        const resolve = (data) => {
            this.#changeState(FULFILLED, data)
         }
        const reject = (reason) => {
            this.#changeState(REJECTED, reason)
         }
        try {
            executor(resolve, reject)
            // 只能捕获同步代码的错误,异步代码的错误无法捕获
        }
        // 如果执行器执行出错,则执行reject 
        catch (err) {
            reject(err)
        }
    }
    // then方法,返回一个新的Promise对象
    then(onFulfilled, onRejected){
        return new MyPromise((resolve, reject) => {
            // 将每次调用then的onFulfilled, onRejected, resolve, reject放到handlers数组中
            this.#handlers.push({
                onFulfilled,
                onRejected,
                resolve,
                reject
            })
            // 调用then方法时run方法
            this.#run()
        })
    }
}

// 示例
const p = new MyPromise((resolve, reject) => {
    setTimeout(()=>resolve(12), 1000);
})
p.then(result => console.log(result), err => console.log(err))
p.then(result => {
    console.log(result)
    return new MyPromise((resolve, reject) => {
        setTimeout(()=>resolve(24), 1000);
    })
}, err => console.log(err))
.then(result => console.log(result))
// 输出:(延迟1秒后)12 12 24 (两个12同时输出,24延迟1秒输出)