Promise 范例解读及完成细节 (二)

最先前

Promise的完成道理已在 Promise 范例解读及完成细节 (一) 中说的很清晰了,这里将详细剖析 Promises/A+范例 中的Promise剖析历程,最后会完成一个 Promise 并供应用于测试的代码

then 要领剖析

promise.then(fn1).then(fn2).then(fn3) 这里 promise.then() 的挪用会发生一个新的promise(差别实例)

关于 then(fn) 上一级 promise 的终值会作为 fn 的参数被传入

关于 then(fn) 假如 then 返回一个 promise1,fn 返回一个 promise2 那末 promise1 的状况和值由 promise2 决议

关于 then(fn) 假如 then 返回一个 promise1,fn 返回一个 promise2 我们想依赖于promise2 的挪用会被增加到 promise1

怎样让 promise2 决议 promise1 的结果

假如promise2thenvar promise2Then = promise2.then,我们如许promise2Then.bind(promise1,resolve,reject)

promise 的状况和终值都是经由过程 当前 promiseresolvereject 来转变的,所以只须要将 promise1 的这两个函数经由过程promise2then 要领增加的 promise2 的实行行列中就能够到达想要的结果

Promise 剖析历程

关于 promise.then(fn),then 要领返回 promise1fn 要领返回 x,fn 接收到的参数为 y,这时候须要对 xy 离别运转Promise剖析历程

x: [[Resolve]](promise1, x)
y: [[Resolve]](promise1, y)
x 的剖析历程处置惩罚的是 回掉中返回 promise 的状况
y 的剖析历程处置惩罚的是 向当前 promise 通报处置惩罚结果的谁人 promise 的终值是 promise 的状况

因而可知 promise 的剖析历程是递归的,递归的尽头是 x,y 不是promise,在是对象或许函数的情况下不具有 then 要领

代码组织

(function(window) {
    var PENDING = 0; //PENDING 状况
    var RESOLVED = 1; //RESOLVED 状况
    var REJECTED = 2; //REJECTED 状况
    function IPromise(fn) {
        if (!(this instanceof IPromise)) return new IPromise(fn); //确保 经由过程 new IPromise() 和 IPromise() 都能准确建立对象
        var state = PENDING; //promise 状况
        var value = null; //终值
        var callback = []; //回掉函数行列,在一种是两个行列,这里是一个,所以寄存的是对象

        function reject(reason) {} //reject 要领
        function resolve(result) {} //和(一)中的对照 这里多了 实行 Promise 剖析历程 的功用
        function handle(handler) {} //增加或实行队 callback 中的挪用

        /**
        *@param onFulfilled 经由过程 then 要领增加的 onFulfilled
        *@param onRejected 经由过程 then 要领增加的 onRejected
        *
        *@func 包装用户增加的回调 
        *因为这里只要一个回掉行列所以须要用 candy(糖果) 包装成{onFulfilled:onFulfilled,onRejected:onRejected}
        *
        *@func 耽误挪用handle
        *在 Promise 范例解读及完成细节 (一) 中说 Promise(浏览器完成) 会被加入到microtask,因为浏览器没有供应除Promise
        *以外microtask的接口,所以 我们要用 setTimeout 来耽误挪用并增加到 macrotask
        *
        */
        function candy(onFulfilled, onRejected) {}

        function getThen(value) {} //推断 value 是不是有 then 要领假如有则猎取

        this.then = function(onFulfilled, onRejected) {} //暴露的 then 要领
        doResolve(fn, resolve, reject); //实行 fn
        window.IPromise = IPromise; //将 IPromise 增加到浏览器的 window 上
    }
    /**
    *Promise 剖析历程
    */
    function doResolve(fn, resolvePromise, rejectPromise) {} //静态私有要领,剖析并实行promise(剖析并实行fn和promise的处置惩罚结果)
})(window);

以上经由过程 js 自实行函数将变量和函数限定在了作用域中,在全局的 window 上只暴露一个组织函数 IPromise 保证了全局不被污染

详细代码及诠释(请在浏览器中运转)

/**
 *@author ivenj
 *@date 2016-12-06
 *@version 1.0 
 */
(function(window) {
    var PENDING = 0;
    var RESOLVED = 1;
    var REJECTED = 2;

    function IPromise(fn) {
        if (!(this instanceof IPromise)) return new IPromise(fn);
        var state = PENDING;
        var value = null;
        var callback = [];

        function reject(reason) {
            state = REJECTED;
            value = reason;
            callback.forEach(handle);
            callback = null;
        }

        /**
        * 这里新增的内容是 满足Promise剖析历程时 resolve和doResolve互相挪用构成递归
        **/
        function resolve(result) {
            try {
                var then = getThen(result);
                if (then) {
                    doResolve(then.bind(result), resolve, reject);  //aa
                    return; //这里假如 resule 是有 then 要领则实行 doResolve 并返回不实行后续代码
                }
                //只要 result 不满足 剖析历程时实行,即递归尽头
                state = RESOLVED;
                value = result;
                callback.forEach(handle);
                callback = null;
            } catch (e) {
                reject(e);
            }
        }

        function handle(handler) {
            if (state === PENDING) {
                callback.push(handler);
            } else {
                if (state === RESOLVED && typeof handler.onFulfilled === 'function') {
                    handler.onFulfilled(value);
                }
                if (state === REJECTED && typeof handler.onRejected === 'function') {
                    handler.onRejected(value);
                }
            }
        }

        function candy(onFulfilled, onRejected) {
            setTimeout(function() {
                handle({
                    onFulfilled: onFulfilled,
                    onRejected: onRejected
                });
            }, 0);
        }

        function getThen(value) {
            var type = typeof value;
            if (value && (type === 'object' || type === 'function')) {
                try{
                    var then = value.then;
                }catch(e){
                    reject(e);
                }
                if (typeof then === 'function') {
                    return then;
                }
            }
            return null;
        }

        this.then = function(onFulfilled, onRejected) {
            var self = this;
            return new IPromise(function(resolve, reject) {
                candy(function(x) {
                    if (typeof onFulfilled === 'function') {
                        try {
                            resolve(onFulfilled(x)); //cc 运转 [[Resolve]](promise, x)
                        } catch (e) {
                            reject(e);
                        }
                    } else {
                        resolve(x);
                    }
                }, function(error) {
                    if (typeof onRejected === 'function') {
                        try {
                            resolve(onRejected(error));
                        } catch (e) {
                            reject(e);
                        }
                    } else {
                        reject(error);
                    }
                });
            });
        };
        doResolve(fn, resolve, reject);
    }

    /**
    *Promise 剖析历程
    */
    function doResolve(fn, resolvePromise, rejectPromise) {
        var done = false; //用于保证只挪用一次
        try {
            fn(function(y) {
                if (done) return;
                done = true;
                resolvePromise(y); //bb 假如 resolvePromise 以值 y 为参数被挪用,则运转 [[Resolve]](promise, y)
            }, function(reason) {
                if (done) return;
                done = true;
                rejectPromise(reason);
            });
        } catch (e) {
            if (done) return;
            done = true;
            rejectPromise(e);
        }
    }
    window.IPromise = IPromise;
})(window);

这里是用于测试的代码 读者将以上代码和以下代码粘贴到浏览器去运转 一秒后会打印 {url: "http://ivenj_", value: 10}

function post(url, callback) {
    setTimeout(function() {
        var data = { //模仿异步处置惩罚结果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}

var promise = IPromise(function(resolve, reject){
    post('http://ivenj_', function(data){
        resolve(data);
    });
});

promise.then(function(data){
    console.log(data);
});

Promise 完成最中心的内容是代码中的 //aa //bb //cc 读者须要偏重体味这三处
Promise 到此已完毕

    原文作者:_ivenj
    原文地址: https://segmentfault.com/a/1190000010234247
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞