手写promise

需要实现的功能:

  • 实现Promise的构造函数 new Promise()
  • 实现类成员方法 then()、catch()
  • 实现类的静态方法 Promise.all()、Promise.race、Promise.deffer()
  • 实现链式调用 resolvePromise()

promise的实现机制:

  1. 通过传一个回调函数去实例化一个promise,里面的回调函数会立即执行
new Promise((resolve,reject) => {
    // 立即执行
})
  1. 在构造器函数中,初始化值,定义决议函数resolve和reject,这两个函数主要是,判断当前状态是否处于pedding状态(避免二次决议),设置相对应的值,若决议是异步的,则事先会去收集成功|失败的回调函数,等到resolve后,遍历执行。
  2. then方法主要是对参数的一个初始化,以及根据不同状态去执行回调函数,值的关注的是即使我们立即resolve(1),promise也是异步执行的,这里用setTimeout来模拟异步调用。
  3. 若决议是异步的,我们调用then时,还未发生决议,就将回调函数分别暂存到响应的数组中,一旦决议,遍历执行即可。
  4. 重头戏是then的链式调用,通过判断回调函数执行后的返回值的类型,来进行判断递归。若是普通值或者对象,则将返回值resolve,传递给下一个链式Promise中
  5. 若返回后任然是一个Promise,则执行它的then方法,在其成功执行回调函数中继续递归调用,直到返回值不是一个Promise为止。
// 三种状态
const PENDDING = "pendding"
const FULLFILED = "fullfied"
const REJECT = "reject"

function resolvePromise(thenPromise, preResult, resolve, reject) {
    if (thenPromise === preResult) return reject(new Error('循环引用'))
    // 1. 如果上一次then中任务执行返回值preResult是一个对象或者function
    //    a. 对象,直接resolve
    //    b. function且是一个Promise,则递归调用
    // 2. 普通数据则直接resolve
    let x = preResult, called = false;
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        let then = x.then
        try {
            // a. 如果是Promise ,调用then方法
            if (typeof then === 'function') {
                // console.log('promise')
                if (called) return
                called = true
                then.call(x, val => {
                    // console.log("返回值",val)
                    resolvePromise(thenPromise, val, resolve, reject)
                }, err => {
                    if (called) return
                    called = true
                    reject(err)
                })

            } else { // b. 如果是普通的对象
                // console.log('普通对象')
                resolve(x)
            }
        } catch (err) {
            if (called) return
            called = true
            reject(err)
        }

    } else {
        // console.log("基本数据或者undefined原样返回")
        resolve(x)
    }

}
class ZPromise {
    static resolve(value) {
        return new ZPromise((resolve, reject) => {
            resolve(value)
        })
    }
    static reject(reason) {
        return new ZPromise((resolve, reject) => {
            reject(reason)
        })
    }
    // 全部
    static all(promises) {
        return new ZPromise((resolve, reject) => {
            let arr = [];
            let i = 0;
            function getResult(index, value) {
                arr[index] = value;
                if (++i == promises.length) {
                    resolve(arr)
                }
            }
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(data => {
                    getResult(i, data)
                }, reject)
            }
        })
    }
    // 第一个
    static race(promises) {
        return new ZPromise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                // resolve后,状态不能改变
                promises[i].then(resolve, reject)
            }
        })
    }
    constructor(cb) {
        this.status = PENDDING;
        this.value = null; // 成功返回值
        this.reason = null;// 失败返回值
        this.fullfiedCbs = []; // 异步时候收集成功回调
        this.rejectCbs = [];// 异步时候收集的失败回调

        let resolve = value => {
            // console.log("进入resolve")
            // 判断当前状态,一旦决议,不允许再改变
            if (this.status === PENDDING) {
                this.status = FULLFILED
                this.value = value
                if (this.fullfiedCbs.length > 0) {
                    this.fullfiedCbs.forEach(cb => cb(this.value))
                }
            }
        }
        let reject = error => {
            if (this.status === PENDDING) {
                this.status = REJECT
                this.reason = error
                if (this.fullfiedCbs.length > 0) {
                    this.rejectCbs.forEach(cb => cb(this.reason))
                }
            }
        }

        cb(resolve, reject)
    }

    catch(onrejected) {
      return this.then(null, onrejected)
    }
    then(onfullfied, onrejected) {
        // console.log('进入then')
        onfullfied = typeof onfullfied === 'function' ? onfullfied : (value => value)
        onrejected = typeof onrejected === 'function' ? onrejected : error => { throw error }
        // 返回一个promise1
        let promise1 = new ZPromise((resolve, reject) => {
            resolveTask = resolveTask.bind(this)
            // 判断状态 决议
            if (this.status === FULLFILED) {
                // console.log('进立即resolve')
                setTimeout(() => resolveTask(onfullfied, resolve, reject), 0)

            }
            if (this.status === REJECT) {
                // console.log('进立即reject')
                setTimeout(() => resolveTask(onrejected, resolve, reject), 0)
            }
            // 1.若promise立即决议,则会直接调用上面的分支
            //2. 若promise resolve或者reject中有异步任务,则执行then方法时,还处于挂起状态,只需要先将回调函数暂存,等待resolve后调用
            if (this.status === PENDDING) {
                // console.log('进pedding')
                this.fullfiedCbs.push(() => setTimeout(() => resolveTask(onfullfied, resolve, reject), 0))
                this.rejectCbs.push(() => setTimeout(() => resolveTask(onrejected, resolve, reject), 0))
            }
        })
        // 执行回调
        function resolveTask(fn, resolve, reject) {
            try {
                let ret = fn(this.value)
                resolvePromise(promise1, ret, resolve, reject)
            } catch (err) {
                reject(err)
            }
        }

        return promise1
    }
}

测试基础功能

const p1 = new ZPromise((resolve, reject) => {
    resolve(1);
});

p1.then(val=>{
    console.log('p1的then', val)
    return {
        name: 1
    }
})

const p2 = new ZPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(2);
    }, 1000)
});
p2.then(val => {
    console.log("p2的then", val)
    return new ZPromise(resolve => {
        console.log("返回值是promise")
        return resolve({
            name: 1
        })
    })
}).then(val => {
    console.log("p2的第二个then", val)
})

测试静态函数

const p1 = new ZPromise((resolve, reject) => {
    resolve(1);
});

const p2 = new ZPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(2)
    }, 1000)
});

const p3 = new ZPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(3);
    }, 3000)
});

ZPromise.race([p1, p2, p3]).then(data => {
    console.log(data); // 1
}, err => {
    console.log(err);
});
ZPromise.all([p2, p1, p3]).then(data => {
    console.log(data); // [2,1,3] 结果顺序和promise实例数组顺序是一致的
}, err => {
    console.log(err);
});

你可能感兴趣的:(JS高级)