promise

/*!
 * 规范:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
 */
(function (global, factory) {
    //UMD处理
    if (typeof define === "function" && define.amd) {
        //AMD
        define(['util'], function (_) {
            return factory(global, _);
        });
    } else if (typeof module === "object" && typeof module.exports === "object") {
        //node/commonJs
        module.exports = factory(global, require('util'), true);
    } else {
        //browser
        factory(global, global._);
    }
})(typeof window !== 'undefined' ? window : this, function (window, _, noGlobal) {
    'use strict';
    if (noGlobal !== true) {
        window.sogou = window.sogou || {};
        window.sogou.Promise = Promise;
    }
    //TODO 
    //if (_.isFunction(window.Promise)) return window.Promise;
    var ON_FUlFILLED = '[[OnFulfilled]]',
        ON_REJECTED = '[[OnRejected]]',
        CHAIN = '[[Chain]]',
        STATUS = {
            PENDING: 2,
            DONE: 1,
            FAIL: 0,
            ERROR: 3
        },
        //判断Promise对象
        isPromise = function (value) {
            return value && typeof value === 'object' && value.constructor === Promise;
        },
        //判断对象是否具有Promise行为
        likePromise = function (value) {
            return value && typeof value === 'object' && _.isFunction(value.then);
        },
        each = Array.prototype.forEach;
    //DEBUG
    //var GUID = 0;

    /*
     * 通过构造函数创建一个Promise对象
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
     * @param {Function} executor - 带有 resolve 、reject两个参数的函数对象。 第一个参数用在处理执行成功的场景,第二个参数则用在处理执行失败的场景。 一旦我们的操作完成即可调用这些函数。
     * @returns {Promise}
     */
    function Promise(executor) {
        if (!(this instanceof Promise)) throw new TypeError("Constructor Promise requires 'new'");
        if (!_.isFunction(executor)) throw new TypeError('Not enough arguments to Promise.');
        this._status = STATUS.PENDING;
        //this._id = GUID++;//DEBUG
        this._isover = false;
        var $this = this;

        //executor的this指向window
        try {
            executor(function (data) {
                //防止反复执行
                if ($this._status !== STATUS.PENDING) {
                    return;
                }
                $this._data = data;
                doCallback($this, $this._status = STATUS.DONE, data);
            }, function (data) {
                if ($this._status !== STATUS.PENDING && $this._status !== STATUS.ERROR) { //如果是error状态,则传递
                    return;
                }
                $this._data = data;
                doCallback($this, $this._status === STATUS.ERROR ? STATUS.ERROR : STATUS.FAIL, data);

            });
        } catch (e) {
            $this._data = e;
            doCallback($this, $this._status = STATUS.ERROR, e);
        }
    };

    /*
     * Promise.prototype.then()方法返回一个Promise。它有两个参数,分别为Promise在 success 和 failure 情况下的回调函数
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
     * @param {Function} onFulfilled - 一个 Function, 当 Promise 为 fulfilled 时调用. 该函数有一个参数, 为成功的返回值.
     * @param {Function} onRejected - 一个 Function, 当 Promise 为 rejected 时调用. 该函数有一个参数, 为失败的原因.
     * @returns {Promise}
     */
    Promise.prototype.then = function (onFulfilled, onRejected) {
        var $this = this,
            newPromise;
        $this[ON_FUlFILLED] = onFulfilled;
        $this[ON_REJECTED] = onRejected;
        return newPromise = new Promise(function (resolve, reject) {
            doCallback($this, $this._status, $this._data, function (data) {
                if (this._status === STATUS.ERROR)
                    newPromise._status = this._status; //=> 传递error
                this._status === STATUS.DONE ? resolve(data) : reject(data);
            });
        });
    };

    /*
     * Promise.prototype.catch() 方法只处理Promise被拒绝的情况,并返回一个Promise。该方法的行为和调用Promise.prototype.then(undefined, onRejected)相同。
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
     * @param {Function} onRejected - 当Promise被拒绝时调用的Function。该函数调用时会传入一个参数:拒绝原因。
     * @returns {Promise}
     */
    Promise.prototype['catch'] = function (onRejected) {
        return this.then(null, onRejected);
    };

    /*
     * Promise.all(promises) 方法返回一个promise,该promise会在promises参数内的所有promise都被解决后被解决。
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
     * @param {Array} promises - 一个Array(ES6规定Promise.all方法的参数不一定是数组,但是必须具有iterator接口)。
     * @returns {Promise}
     */
    Promise.all = function (promises) {
        if (!_.isArrayLike(promises)) {//不是arrayLike则无法循环
            throw new TypeError("Argument 1 of Promise.all can\'t be converted to a sequence");
        }
        return new Promise(function (resolve, reject) {
            var res = [],
                //剩余完成的
                thenableCount = 0;
            each.call(promises, function (item, i) {
                //具有promise行为
                if (likePromise(item)) {
                    thenableCount++;
                    res.push(0);
                    item.then(function (data) {
                        //当thenableCount为0表示所有的Promise行为都已完成
                        thenableCount--;
                        res[i] = data;
                        //防止这个promise的长度在循环中产生变动
                        promises.length === res.length && !thenableCount && resolve(res);
                    }, function (data) {
                        reject(data);
                    });
                } else {
                    res.push(item);
                    promises.length === res.length && !thenableCount && resolve(res);
                }

            })
        })

    };

    /*
     * Promise.race(promises)方法返回一个promise,这个promise在promises中的任意一个promise被解决或拒绝后,立刻以相同的解决值被解决或以相同的拒绝原因被拒绝。
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
     * @param {Array} promises -  - 一个Array(ES6规定Promise.race方法的参数不一定是数组,但是必须具有iterator接口).
     * @returns {Promise}
     */
    Promise.race = function (promises) {
        if (!_.isArrayLike(promises)) {//不是arrayLike则无法循环
            throw new TypeError("Argument 1 of Promise.race can\'t be converted to a sequence");
        }
        return new Promise(function (resolve, reject) {
            var i = 0,
                item;
            for (; i < promises.length; i++) {
                item = promises[i];
                if (likePromise(item)) //具有Promise行为
                    item.then(resolve, reject)
                else {
                    //直接完成
                    resolve(item);
                    break;
                }
            }
        });
    };

    /*
     * Promise.resolve(value)方法返回一个以给定值resolve掉的Promise对象。但如果这个值是thenable的(就是说带有then方法)
     * 返回的promise会“追随”这个thenable的对象,接收它的最终状态(指resolved/rejected/pendding/settled);否则这个被返回的promise对象会以这个值被fulfilled
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
     * @param {Object | Promise} value - 用来resolve待返回的promise对象的参数。既可以是一个Promise对象也可以是一个thenable。
     * @returns {Promise}
     */
    Promise.resolve = function (value) {
        if (isPromise(value)) return value;
        if (likePromise(value)) {
            return new Promise(function (resolve, reject) {
                value.then(resolve, reject);
            });
        }
        return new Promise(function (resolve) {
            resolve(value);
        });
    };

    /*
     * Promise.reject(reason)方法返回一个用reason拒绝的Promise。
     * 静态函数Promise.reject返回一个被拒绝的Promise。使用是Error实例的reason对调试和选择性错误捕捉很有帮助。
     * 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
     * @param {Object | Promise} value - Promise被拒绝的原因。
     * @returns {Promise}
     */
    Promise.reject = function (value) {
        return new Promise(function (resolve, reject) {
            reject(value);
        });
    };


    //回调中心处理
    function doCallback(promise, status, data, callback) {
        //setTimeout();
        _.nextTick(function () { //挂起异步,让promise其他的代码先执行
            //doCallback有多个入口,当一个任务完成后阻塞住其他任务
            if (promise._isover) {
                if (_.isFunction(callback)) //已完成,有回调函数,直接调用
                    callback.call(promise, data);
                return;
            };
            //有回调链
            if (promise[CHAIN] && !callback) {
                callback = promise[CHAIN];
            }
            if (status === STATUS.PENDING || (!promise[ON_FUlFILLED]) && !promise[ON_REJECTED]) { //状态标志完成、回调函数也已经委托,才可以继续执行,否则被拦截
                if (status === STATUS.ERROR && data) {
                    //没有then链的回调函数,并且有error信息,则抛出(即最后一个then,且木有捕获异常,所以这里直接终止状态)
                    promise._isover = true;
                    throw data;
                }
                //挂起回调链
                promise[CHAIN] = callback;
                return;
            };
            var func = status === STATUS.DONE ? resolve : reject;
            try {
                nextTickCallback(promise, func, data, status, callback)
            } catch (e) {
                //catch处理
                promise._isover = true;
                promise._status = STATUS.ERROR;
                promise._data = e;
                if (_.isFunction(callback))
                    callback.call(promise, e);
            }
        });
    }

    function nextTickCallback(promise, func, data, status, callback) {
        if (promise._isover) return;
        promise._status = status;
        var res = func(promise, data);
        if (res instanceof Promise) {
            res.then(function (value) {
                _.isFunction(callback) && callback.call(res, value);
            }, function (value) {
                _.isFunction(callback) && callback.call(res, value);
            });
        } else if (_.isFunction(callback))
            callback.call(promise, res);
    };

    function resolve(promise, data) {
        //promise只支持一个参数
        var res;
        if (_.isFunction(promise[ON_FUlFILLED])) {
            res = promise[ON_FUlFILLED](data);
            promise._isover = true;
        }
        return res;
    };

    function reject(promise, data) {
        var res;
        if (_.isFunction(promise[ON_REJECTED])) {
            res = promise[ON_REJECTED](data);
            //修正Error状态
            promise._status = STATUS.FAIL;
            promise._isover = true;
        } else {
            res = data;
            promise._isover = true;
        }
        return res;
    };

});
复制代码

(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        //AMD
        define("util", [], function () {
            return factory(global);
        });
    } else if (typeof module === "object" && typeof module.exports === "object") {
        //node/commonJs
        module.exports = factory(global, true);
    } else {
        //browser
        factory(global);
    }
})(typeof window !== 'undefined' ? window : this, function (window, noGlobal) {
    'use strict';
    var toString = Object.prototype.toString,
        util = {
            isFunction: function (value) {
                return toString.call(value) === '[object Function]';
            },
            isArrayLike: function (obj) {
                if (obj == null) return false;
                var length = obj.length, t = toString.call(obj);
                return t === '[object Array]' || length === 0 || !util.isFunction(obj) &&
                t !== '[object String]' && //解决TypeError:invalid 'in' operand obj,字符串不允许使用in
                (+length === length && //正数
                !(length % 1) && //整数
                (length - 1) in obj); //可以被索引,防止0引发bug
            },
            nextTick: new function () {
                //自动尝试浏览器最优线程执行
                var tickObserver = window.MutationObserver,
                    tickChannel = window.MessageChannel,
                    tickSetImmediate = window.setImmediate;
                //任务队列
                var queue = [];
                function callback() {
                    //TODO 线程并不安全,没有锁线程
                    var n = queue.length;
                    for (var i = 0; i < n; i++) {
                        queue[i]();
                    }
                    queue = queue.slice(n);
                }
                if (tickSetImmediate) {
                    //console.log('nextTick - tickSetImmediate');
                    return function (func) {
                        queue.push(func);
                        window.setImmediate(func);
                        return util;
                    }
                }
                if (tickChannel) {
                    //console.log('nextTick - MessageChannel');
                    tickChannel = new window.MessageChannel();
                    tickChannel.port1.onmessage = function () {
                        callback();
                    };
                    return function (func) {
                        queue.push(func);
                        tickChannel.port2.postMessage(0);
                        return util;
                    }
                }
                if (tickObserver) {
                    //console.log('nextTick - 支持监听DOM树');
                    var node = document.createTextNode("service")
                    new tickObserver(callback).observe(node, { characterData: true })
                    return function (func) {
                        queue.push(func)
                        node.data = Math.random();
                        return util;
                    }
                }
                return function (func) {
                    setTimeout(func, 0);
                    return util;
                }
            }
        };
    if (typeof noGlobal !== true) {
        window._ = util;
    }
    return util;
});


复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值