很多大厂在面试的时候都喜爱让面试者手写promise,所以有时候咱们也要面向面试编程。

要想实现本人的promise,首先咱们看看官网promise的用法,请看上面这段代码:

const foo = () => {  return new Promise((resolve, reject) => {      setTimeout(() => {          resolve('111')      }, 1000);  })}foo().then((res) => {  console.log(res);})console.log('hello');// 先输入 'hello' 再输入 '111'

首先,咱们依据这段代码,来梳理下思路:

  1. 先申明一个class类,咱们叫它 MyPromise;
  2. MyPromise类承受一个函数fn作为参数,且fn有两个参数resolvereject,均为函数;
  3. 定义MyPromise类的三种状态,pendingfulfilledrejected;
  4. MyPromise类的constructor里要执行函数fn, 把resolvereject传递给fn,执行resolvereject时要扭转MyPromise类的状态;
  5. 实现then办法,then办法接管两个函数作为参数;
  6. 实现链式调用;

接下来让咱们用代码实现。

第一步:

// 定义MyPromise的三种状态        const PENDING = 'pending';        const FULFILLED = 'fulfilled';        const REJECTED = 'rejected';        class MyPromise {            // 类的属性能够间接定义在顶层            status = PENDING; // 初始状态设为 pending            result = undefined; // resolve传递的后果            reason = undefined; // reject传递的后果            constructor(fn) {                // 定义resolve函数                const resolve = (result) => {                    // 只有是pending状态能力批改为fulfilled状态                    if (this.status === PENDING) {                        // 把后果存起来,同时扭转状态                        this.result = result;                        this.status = FULFILLED;                    }                }                // 定义reject函数                const reject = (reason) => {                    // 只有是pending状态能力批改为rejected状态                    if (this.status === PENDING) {                        // 把后果存起来,同时扭转状态                        this.reason = reason;                        this.status = REJECTED;                    }                }                // new的时候接管的函数,立刻执行                fn(resolve, reject);            }        }

解释:其实就是定义了一个类,而后定义了构造函数,构造函数承受一个函数,并立刻执行,其实这也是 new 操作的根本过程;

第二步:

// 定义MyPromise的三种状态const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED = 'rejected';class MyPromise {    // 类的属性能够间接定义在顶层    status = PENDING; // 初始状态设为 pending    result = undefined; // resolve传递的值    reason = undefined; // reject传递的值    constructor(fn) {        // 定义resolve函数        const resolve = (result) => {            // 只有是pending状态能力批改为fulfilled状态            if (this.status === PENDING) {                // 把后果存起来,同时扭转状态                this.result = result;                this.status = FULFILLED;            }        }        // 定义reject函数        const reject = (reason) => {            // 只有是pending状态能力批改为rejected状态            if (this.status === PENDING) {                // 把后果存起来,同时扭转状态                this.reason = reason;                this.status = REJECTED;            }        }        // new的时候接管的函数,立刻执行        fn(resolve, reject);    }        // 定义then办法 接管两个函数作为参数    then(onResolve, onReject) {        // 如果状态为 fulfilled , 执行onResolve, 并把执行resolve函数时存的后果传入        if(this.status === FULFILLED) {            onResolve(this.result);        }        // 如果状态为 rejected , 执行onReject, 并把执行reject函数时存的后果传入        if(this.status === REJECTED) {            onReject(this.reason)        }    }}

解释:相比第一步,减少了then办法,then办法其实很简略,承受两个函数并执行,这两个函数的参数是类的resultreason属性值,其实也就是执行resolvereject函数时,传入的值;

这时候MyPromise的基本功能曾经实现(开心),让咱们来试用一下:

const foo = () => {  return new MyPromise((resolve, reject) => {      setTimeout(() => {          resolve('111')      }, 1000);  })}foo().then((res) => {  console.log(res);})console.log('hello');// 输入 'hello'

等等,貌似有点不对!怎么只输入了‘hello’而没有输入‘111’呢?

遇到事件不要慌,咱们来捋一下逻辑:

从最近的代码片段能够看出,resolve函数是在setTimeout里延时了1秒钟执行的,而then办法是同步执行的,是在resolve执行之前就执行了,这时候MyPromise的状态还是'pending',所以基本就没有执行onResolve办法,天然就没有打印'111';

找到了起因所在,接下来咱们就革新下then办法:

// 定义MyPromise的三种状态const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED = 'rejected';class MyPromise {    // 类的属性能够间接定义在顶层    status = PENDING; // 初始状态设为 pending    result = undefined; // resolve传递的值    reason = undefined; // reject传递的值    onResolveArr = []; // 存入then办法的第一个参数onResolve,期待状态变为fulfilled的时候再去执行;    onRejectArr = []; // 存入then办法的第二个参数onReject,期待状态变为rejected的时候再去执行;    constructor(fn) {        // 定义resolve函数        const resolve = (result) => {            // 只有是pending状态能力批改为fulfilled状态            if (this.status === PENDING) {                // 把后果存起来,同时扭转状态                this.result = result;                this.status = FULFILLED;                // 执行resolve时,把所有存入onResolveArr的函数都执行一遍                this.onResolveArr.map(onResolve => onResolve());            }        }        // 定义reject函数        const reject = (reason) => {            // 只有是pending状态能力批改为rejected状态            if (this.status === PENDING) {                // 把后果存起来,同时扭转状态                this.reason = reason;                this.status = REJECTED;                // 执行reject时,把所有存入onRejectArr的函数都执行一遍                this.onRejectArr.map(onReject => onReject());            }        }        // new的时候接管的函数,立刻执行        fn(resolve, reject);    }        // 定义then办法 接管两个函数作为参数    then(onResolve, onReject) {        // 如果状态为pending, 临时先把onResolve、onReject存入对应的数组里        // 为什么要存到数组里?因为new MyPromise()可能会调用多个then办法(留神这里不是链式调用)        if(this.status === PENDING) {            // 因为onResolve、onReject要承受参数,所以这里要push一个匿名函数;            this.onResolveArr.push(() => {                onResolve(this.result);            })            this.onRejectArr.push(() => {                onReject(this.reason);            })        }        // 如果状态为 fulfilled , 执行onResolve, 并把执行resolve函数时存的后果传入        if(this.status === FULFILLED) {            onResolve(this.result);        }        // 如果状态为 rejected , 执行onReject, 并把执行reject函数时存的后果传入        if(this.status === REJECTED) {            onReject(this.reason)        }    }}

解释:能够看到,在then办法里新增了一个判断,当状态为pending的时候,把onResolve、onReject存入对应的数组中,以便在未来执行resolvereject的时候去执行,相似于设计模式中的公布、订阅模式

这个时候,then办法根本就实现了,再执行方才那个例子,发现能够失常的返回'hello''111'了。

But!当初还不能链式调用,因为当初then办法并没有返回值,所以在执行第二个then办法时会报错Cannot read properties of undefined,接下来咱们持续实现链式调用:

// 定义MyPromise的三种状态const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED = 'rejected';class MyPromise {    // 类的属性能够间接定义在顶层    status = PENDING; // 初始状态设为 pending    result = undefined; // resolve传递的值    reason = undefined; // reject传递的值    onResolveArr = []; // 存入then办法的第一个参数onResolve,期待状态变为fulfilled的时候再去执行;    onRejectArr = []; // 存入then办法的第二个参数onReject,期待状态变为rejected的时候再去执行;    constructor(fn) {        // 定义resolve函数        const resolve = (result) => {            // 只有是pending状态能力批改为fulfilled状态            if (this.status === PENDING) {                // 把后果存起来,同时扭转状态                this.result = result;                this.status = FULFILLED;                // 执行resolve时,把所有存入onResolveArr的函数都执行一遍                this.onResolveArr.map(onResolve => onResolve());            }        }        // 定义reject函数        const reject = (reason) => {            // 只有是pending状态能力批改为rejected状态            if (this.status === PENDING) {                // 把后果存起来,同时扭转状态                this.reason = reason;                this.status = REJECTED;                // 执行reject时,把所有存入onRejectArr的函数都执行一遍                this.onRejectArr.map(onReject => onReject());            }        }        // new的时候接管的函数,立刻执行        fn(resolve, reject);    }    // 解决何时执行第二个promise的resolve、reject函数    handleNewPromise(res, newPromise, resolve, reject) {        // 如果第一个then函数返回的值是以后promise,则会产生循环援用        if (res === newPromise) {            return reject(new TypeError('Chaining cycle detected for promise'))        }        // 避免屡次调用        let called;        // 如果是对象类型或函数类型        if (typeof res === 'object' || typeof res === 'function') {            // 获取第一个then办法的返回值的then属性,如果是个函数,则默认为promise            const then = res.then;            // 如果res是promise,则间接执行then办法            if (typeof then === 'function') {                // 传入this、新的onResolve、新的onReject                then.call(res, newRes => {                    // 胜利和失败只能调用一个                    if (called) return;                    called = true;                    // 递归调用handleNewPromise  直到res不是object或function                    this.handleNewPromise(newRes, newPromise, resolve, reject);                }, newReason => {                    // 胜利和失败只能调用一个                    if (called) return;                    called = true;                    reject(newReason);                })            } else {                resolve(res);            }        } else {            // 如果是值类型  间接执行第二个promise的resolve办法  并把后果返回            resolve(res);        }    }    // 定义then办法 接管两个函数作为参数    then(onResolve, onReject) {        // then办法返回一个新的promise,以便于链式调用        const newPromise = new MyPromise((resolve, reject) => {            // 如果状态为pending, 临时先把onResolve、onReject存入对应的数组里            // 为什么要存到数组里?因为new MyPromise()可能会调用多个then办法(留神这里不是链式调用)            if (this.status === PENDING) {                // 因为onResolve、onReject要承受参数,所以这里要push一个匿名函数;                this.onResolveArr.push(() => {                    const result = onResolve(this.result);                    this.handleNewPromise(result, newPromise, resolve, reject);                })                this.onRejectArr.push(() => {                    const reason = onReject(this.reason);                    this.handleNewPromise(reason, newPromise, resolve, reject);                })            }            // 如果状态为 fulfilled , 执行onResolve, 并把执行resolve函数时存的后果传入            if (this.status === FULFILLED) {                const result = onResolve(this.result);                this.handleNewPromise(result, newPromise, resolve, reject);            }            // 如果状态为 rejected , 执行onReject, 并把执行reject函数时存的后果传入            if (this.status === REJECTED) {                const reason = onReject(this.reason);                this.handleNewPromise(reason, newPromise, resolve, reject);            }        })        return newPromise;    }}

解释:then办法返回了新的promise, 新增了handleNewPromise办法,次要是判断第一个then函数的返回后果,而后依据不同类型,做相应的具体操作,其实次要是判断第一个then的返回后果是不是promise,如果是的话,递归调用handleNewPromise办法。

到这里,曾经根本实现本人的promise了,当然这不是残缺的,还有一些中央须要做兼容解决,有想法能够在评论区探讨哦~