Promise的简单实现

1、Promise在javascript中的重要性不言而喻,但很多同学并不清楚内部的实现机理,我就我的理解与大家分享一下;

2、最简单的办法就是根据官方的Promise效果来实现相同的效果,我之前也看过网上的相关实现,全篇看到底就懵了,我想能不能出浅入深一步一步来;

3、好了,先实现一个最简单的,只实现then方法,能够根据resolve与reject取到相关结果,仅做功能实现,后续再完善

1、promise.js

/**
 * Promise简单实现 v0.0.1
 *
 * Date:2020-09-24
 *
 * Author:yusian
 */
(function (window) {
    /**
     * Promise状态值
     */
    const PROMISE_STATE = {
        PENDING: 'pending',
        FILFULLED: 'filfulled',
        REJECTED: 'rejected'
    }
    /**
     * 构造函数,生成一个Promise对象,参数为函数
     * 传入的函数带有2个参数,分别为resolve与reject
     * resolve为带有value值的成功回调
     * reject为带有reason值的失败回调
     * @param {Function} excutor 执行器函数
     */
    function Promise(excutor) {
        let self = this;
        this.state = PROMISE_STATE.PENDING;
        this.data = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];

        /**
         * 成功回调
         * @param {any} value 成功回调值
         */
        function resolve(value) {
            if (self.state !== PROMISE_STATE.PENDING) return;
            self.state = PROMISE_STATE.FILFULLED;
            self.data = value;
            self.onResolvedCallbacks.forEach(function (callback) {
                callback(value);
            })
        }

        /**
         * 失败回调
         * @param {any} reason 失败回调值或Error
         */
        function reject(reason) {
            if (self.state !== PROMISE_STATE.PENDING) return;
            self.state = PROMISE_STATE.REJECTED;
            self.data = reason;
            self.onRejectedCallbacks.forEach(function (callback) {
                callback(reason);
            })
        }

        /**
         * 同步执行异步任务,如有异常及时抛出并结束任务,调用失败回调
         */
        try {
            excutor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }
    /**
     * Promise回调,异步任务执行结束后会执行该回调
     * 该方法调用可以在异步执行结束前或结束后,不影响回调
     * @param {Function} onResolve 成功回调
     * @param {Function} onReject 失败回调
     */
    Promise.prototype.then = function (onResolve, onReject) {
        let self = this;
        // 如果是pending状态,则暂时将回调加入到队列中等待执行
        if (self.state === PROMISE_STATE.PENDING) {
            self.onResolvedCallbacks.push(function () {
                setTimeout(function () { onResolve(self.data); })
            })
            self.onRejectedCallbacks.push(function () {
                setTimeout(function () { onReject(self.data); })
            })
        }
        // 如果是filfulled状态,则执行传入的onResolve函数
        else if (self.state === PROMISE_STATE.FILFULLED) {
            setTimeout(function () { onResolve(self.data); });
        }
        // 如果是rejected状态,则执行传入的onReject函数
        else if (self.state === PROMISE_STATE.REJECTED) {
            setTimeout(function () { onReject(self.data); });
        }
    }
    /**
     * 全局访问
     */
    window.Promise = Promise;
})(window)

2、index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise简单实现</title>
    <script src="lib/promise.js"></script>
</head>

<body>
    <script>
        console.log(1);
        let p = new Promise(function (resolve, reject) {
            console.log(2);
            resolve(2);
        });
        console.log(p);
        p.then(function (value) {
            console.log(4);
            console.log('onResolve:', value);
        }, function (reason) {
            console.log(4);
            console.log('onReject:', reason);
        })
        console.log(3);
    </script>
</body>

</html>

控制台输出结果:

1
2
Promise {}
3
4
onResolve: 2

解释说明:
* 为什么需要Promise?传统的的异步任务需要在执行前传入回调函数来获取结果,这很不方便,也不灵活,比如能不能在我指定的时机回调?我要多点触发怎么办?
* Promise中的重点是将异步任务中的回调方法结果分别在promise对象中保存,在 适当 的时机进行回调,这让任务的执行与结果的处理进行了分离;
* 当前只是实现了then方法,可以获取异步任务的resolve或reject回调,但还不支持链式调用,也没有实现catch方法;
* 相关说明已经注释中标明,对于理解Promise应该有所帮助。

Leave a Reply