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 = 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 = 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 = 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 = 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 = 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 = 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;

Javascript Promise 学习

时间: 2024-08-28 12:26:20

Javascript Promise 学习的相关文章

Javascript Promise 学习 (中)

时隔多日,对promise有了多一点点的了解. 最近用angularjs 做开发,所以研究了一下它的 $q 功能不算很强大,算是简化版的 Q.js 参考了一下源码,不过我的等级还差很多... 作为学习,我自己又重写了一篇. 这次的比较整齐.代码也少了 . $q = function (asyncFn) { var defer = new Deferred(); asyncFn(defer.resolve.bind(defer), defer.reject.bind(defer)); return

javascript Promise学习

目录 Promise 基础语法 三种状态 Promise原型方法 Promise.prototypr.then() Promise.prototype.catch() Promise.prototype.finally() Promise 的属性和方法 Promise.all(iterable) Promise.race(iterable) Promise.resolve(value) Promise.reject(err) Promise Promise 是ES6新增的对象,用来处理异步,使用

javascript基础学习(十五)

javascript之cookie 学习要点: cookie介绍 创建与获取cookie cookie的编码 cookie的生存期 cookie的路径 cookie的domain cookie的secure 一.cookie介绍 cookie实际上就是一些信息,这些信息以文件的形式存储在客户端计算机上.在javascript中,cookie主要用来保存状态,或用于识别身份. 二.创建与获取cookie 创建cookie的语法代码如下所示:document.cookie="name=value&q

javascript基础学习(八)

javascript之日期对象 学习要点: 日期对象 将日期对象转换为字符串 将日期对象中的日期和时间转换为字符串 日期对象中的日期 日期对象中的时间 设置日期对象中的日期 设置日期对象中的时间 与毫秒相关的方法 一.日期对象 在javascript中并没有日期型的数据类型,但是提供了一个日期对象可以操作日期和时间. 日期对象的创建: new Date(); 二.将日期对象转换为字符串 将日期对象转换为字符串可以使用以下4种方法: date.toString();//将日期对象转换为字符串时,采

javascript基础学习(二)

javascript的数据类型 学习要点: typeof操作符 五种简单数据类型:Undefined.String.Number.Null.Boolean 引用数据类型:数组和对象 一.typeof操作符 typeof操作符用来检测变量的数据类型,操作符可以操作变量也可以操作字面量. 对变量或值运用typeof操作符得到如下值: undefined----如果变量是Undefined类型: boolean-------如果变量是Boolean类型: number-------如果变量是Numbe

javascript小白学习指南0---1

引言: 做为一名程序员,都是真心的想把自己的东西分享出来,供大家一起学习探讨,一起提高技能,一起涨工资,呵 这一系列的文章都是关于Javascript 基础的 当然文章当中穿插了些我自己的理解,希望可以帮助一些刚开始的童鞋! 废话不多说我们开始吧! 第一章:Javascript 基本概念 主要内容 数据类型 控制语句 函数 我们先从最简单的数据类型开始吧! 首先请记住javascript 有5种基本数据类型和1种复杂数据类型,至于为什么只有这六种,大家可以去翻翻W3C的资料哈! 五种基本数据类型

初步总结javascript中学习DOM之前的知识

嘿嘿,又到了周末时间,周六其实就是总结这周的学习的,记得周二周三刚开始接触javascript时间,还是不知道怎么学习的,就感觉找不到方向,那时间学习的只是总结了一些简单的定义或者是学习结构,今天就把这些重新练习了一下,感觉还是蛮容易找到学习的兴趣的,顿时就默默的开始了今天的练习过程.今天就总结下初步认识javascript时间的一些实例,记得前面总结的并不完全,所以在这里总结一下基本概念. 一.基本的认识一些类型和方法 <script> var colors = new Array(3);

JavaScript入门学习书籍的阶段选择

对于许多想学习 JavaScript 的朋友来说,无疑如何选择入门的书籍是他们最头疼的问题,或许也是他们一直畏惧,甚至放弃学习 JavaScript 的理由.在 JavaScript 方面,自己不是什么专家,也不是什么高手,但自己一路走来,JavaScript 从迷茫到认识,对于JavaScript 书籍的认识或许还有些借鉴价值.入门推荐首选书籍:<JavaScript DOM 编程艺术>当初读了不下 4 遍,书内容简单,易学,上手快,编程思想严谨.好的入门书,对你未来的编程都会有着深远的影响

[转载] 几张非常有意义的JavaScript基础学习思维图

原文:http://www.w3cfuns.com/forum.php?mod=viewthread&tid=5598364&extra=page%3D1%26filter%3Ddigest%26digest%3D1%26digest%3D1 1.JavaScript 数组 2.JavaScript 函数基础 3.Javascript 运算符 4.JavaScript 流程控制 5.JavaScript 正则表达式 6.JavaScript 字符串函数 7.JavaScript 数据类型