首页 > 代码库 > Javascript Promise 学习

Javascript Promise 学习

Promise 就是处理异步的一个规范方法

a();
b();
alert("a");
如果a() 里面有一个ajax 或者settimeout 
那么alert("a") 会先跑
这就是异步了。
从前我们用一堆callBack函数来解决问题,但是这样写不好看。
promise 的写法美丽多了
依据上面的例子
a().then(b).then(function(){
alert("");
})
这样它会先跑完 a -> b - > alert("");

虽然很多类库都实现了这个功能,甚至游览器也有自带的,而且ecma6好像还会有更好更简单的方法来解决异步的操作 ! 
but ! 人生最鸡巴的就是这个 but! 
当作学习,我还是自己写了一个版本。
这个版本不是 promise a 也不是promise a+ 也不是jQuery Defferd 规范
它是给我自己用的!

个人觉得重点思想就是在 then 的时候返回一个 next promise , 而next promise 记入在上一个promise中,这样就创建了一个promise 连环链

而一个回调函数返回的是promise 或者我们叫thenAble函数,那么我们就把原先的链连接去它的后面就可以了。 

     function Promise(fn) {        //如果有放fn进来,那么就调用它,把 pass & fail 做参数传进去        //这样fn 内就可以直接 publish了         if (G.isFunction(fn)) {            var promise = new Promise();            fn.apply(null, [promise.pass.bind(promise), promise.fail.bind(promise)]);            return promise;        }        this.status = "pending";        this.data;        this._nextPromise; //保存下一个的指针,这样才可以连环触发        this._passFn_list = [];        this._failFn_list = [];        this._isAllPassRequest = true; //all or any 用的        //注释        //要改要潜水        //这里只说简单的使用说明吧         /*        //方便的初始化调用法        new Promise(function (pass, fail) {            setTimeout(pass, 100, "zzz"); //第三para是传给方法的参数 = pass(zzz)        }).then(fnPass, fnFail);        //一般调用法        a().then(b).then(c);        function a() {            var promise = new Promise();            setTimeout(function () {                promise.pass("data");            }, 1000);            return promise;        }        //all 和 any 参数是array,它会并发处理         //等待全部处理完验证每个的返回        //unknow 算 true         //(note: 一个promise只保存all or any 1condition default是 all)        //如果要求是 all ,那么回来的全部都必须all 就调用nextPromise.pass else fail        //如果要求是 any ,那么回来的要有至少一个是pass 就调用nextPromise.pass else fail        a().all([b, c], [c, b]).then(b, c);        //.catch, .complete 都是语法糖罢了            //异步loop调用, 这个比较复杂,以后还可以有更多变化        var list = [a, a, a];        var promiseTemp;        for (var i = 0; i < list.length; i++) {            var promise = (promiseTemp == undefined) ? list[i]() : promiseTemp.then(list[i]);            promiseTemp = promise;        }        */        //简单说明:        /*        两大关键方法        then : 把参数加入fn_list中, 然后new 新的promise, 当前的promise.next 指向新的promise(循环链就开始了) ,然后把新的promise 返回出去        pass/fail : 把fn_list中的方法全部拿出来,然后"并发处理", 检查每一个是不是返回promise, 是的话要记入和跟踪,跟踪其实就是为这个promise加一个then,然后把职责链放进去,交替的感觉。             调用then/all/any的时候如果promise的status不是pending会直接add and 发布data        在并发方法之后 fnList会被清除干净,也就是说一个promise的fnlist的每个方法只会被执行一次        */    }    Promise.prototype._concatFnList = function (passFn_list, failFn_list) {        //all 和 any 用来concat fn list 的        if (passFn_list != undefined && Array.isArray(passFn_list)) {            this._passFn_list = this._passFn_list.concat(passFn_list);        }        if (failFn_list != undefined && Array.isArray(failFn_list)) {            this._failFn_list = this._failFn_list.concat(failFn_list);        }    }    Promise.prototype._getFinalDataByDataRecordList = function (dataRecord_list) {        //dataRecord_list 是array , 因为大部分时候我们是用一个data罢了,所以这边做一些小过滤        var finalValue;        if (dataRecord_list.length == 1) {            finalValue = dataRecord_list[0].data; //抽取data出来就够了        }        else {                    dataRecord_list.orderBy("index");//排好位置(因为all/any是并发,不会按照顺序回来)            finalValue = http://www.mamicode.com/dataRecord_list.map(function (obj) {                delete obj.index; //洗掉属性 index 排位之后就没用了                return obj;            });        }        return finalValue;    }    Promise.prototype._publish = function (fn_list, that) {        //pass 和 fail 的共用过程        if (fn_list.length > 0) {            var returnPromiseCountRecord = 0; //for all & any 多个并发,同时会有多个promise函数            var dataRecord_list = []; //收集全部函数回来的data {index,data,status}                                          for (var i = 0, l = fn_list.length; i < l; i++) {                var fn = fn_list[i];                var returnValue = http://www.mamicode.com/fn.call(that, that.data); //挺关键的一句,这里会确定他返回的是不是promise                (function (i) {                    function callBack(data) {                        //这里是我们外面的promise链 publish触发的                         var result = { index: i, status: this.status, data: data };                        dataRecord_list.push(result) //record data                        returnPromiseCountRecord--; //之前我们累加计算,这里publish了就要开始累减回去了                        //一直到0就准备做ending然后继续外面的职责链了                        if (returnPromiseCountRecord == 0) {                            var is_allPass = dataRecord_list.every(function (v) {                                return (v.status == "unknow" || v.status == "pass");                            });                            var is_anyPass = dataRecord_list.some(function (v) {                                return (v.status == "unknow" || v.status == "pass");                            });                            var finalValue =http://www.mamicode.com/ that._getFinalDataByDataRecordList(dataRecord_list);                            //这里会依据 all or any 做处理 觉得调用下一家的 pass or fail                            if ((that._isAllPassRequest && is_allPass) || (!that._isAllPassRequest && is_anyPass)) {                                that._nextPromise.pass(finalValue);                            }                            else {                                that._nextPromise.fail(finalValue);                            }                        }                    }                    if (returnValue instanceof Promise) {                        //是promise的话就要 +count,然后+then给他,把职责链给他,等待他触发                        returnPromiseCountRecord++;                        var otherPromise = returnValue;                        otherPromise.complete(callBack);                    }                    else {                        //不是的话就push data 就好,status : unknow 也算 pass                        var result = { index: i, status: "unknow", data: returnValue };                        dataRecord_list.push(result);                    }                })(i)            }            fn_list.length = 0; //运行完就clear掉            //没有return任何thenable方法            if (returnPromiseCountRecord == 0) {                var finalValue =http://www.mamicode.com/ that._getFinalDataByDataRecordList(dataRecord_list);                that._nextPromise.pass(finalValue); //因为没有pass fail 参考所以一定是pass             }        }        else {            //如果没有效应就去找小一家promise效应            if (that._nextPromise) {                that._nextPromise[that.status](that.data);            }        }    }    Promise.prototype.all = function (passFn_list, failFn_list) {        this._concatFnList(passFn_list, failFn_list);        if (this.status != "pending") this._alreadyPublish();        return this._nextPromise || (this._nextPromise = new Promise());    }    Promise.prototype.any = function (passFn_list, failFn_list) {        this._concatFnList(passFn_list, failFn_list);        this._isAllPassRequest = false;        if (this.status != "pending") this._alreadyPublish();        return this._nextPromise || (this._nextPromise = new Promise());    }    Promise.prototype.then = function (passFn, failFn) {        if (passFn != undefined) this._passFn_list.push(passFn);        if (failFn != undefined) this._failFn_list.push(failFn);        if (this.status != "pending") this._alreadyPublish();        return this._nextPromise || (this._nextPromise = new Promise());    }    Promise.prototype._alreadyPublish = function () {        var that = this;        setTimeout(function () {            that[that.status](that.data);        }, 0);    }    Promise.prototype.pass = function (data) {        var that = this;        this.status = "pass";        this.data =http://www.mamicode.com/ data;        var passFn_list = this._passFn_list;        that._publish(passFn_list, that);    }    Promise.prototype.fail = function (data) {        var that = this;        this.status = "fail";        this.data =http://www.mamicode.com/ data;        var failFn_list = this._failFn_list;        that._publish(failFn_list, that);    }    Promise.prototype.complete = function (completeFn) {        return this.then(completeFn, completeFn);    }    Promise.prototype.catch = function (catchFn) {        return this.then(void 0, catchFn);    }    Promise.prototype.getLastPromise = function () {        var promise = this;        for (var i = 0; i < Number.MAX_VALUE; i++) {            if (promise._nextPromise === undefined) {                return promise;            }            else {                promise = promise._nextPromise;            }        }    }    G.s.Promise = Promise;