zoukankan      html  css  js  c++  java
  • 浅谈Javascript中Promise对象的实现

    https://segmentfault.com/a/1190000000684654

    What?

    PromiseCommonJS的规范之一,拥有resolverejectdonefailthen等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套。如今异步在web开发中越来越重要,对于开发人员来说,这种非线性执行的编程会让开发者觉得难以掌控,而Promise可以让我们更好地掌控代码的执行流程,jQuery等流行的js库都已经实现了这个对象,年底即将发布的ES6也将原生实现Promise

    Why

    想象这样一个场景,两个异步请求,第二个需要用到第一个请求成功的数据,那么我们代码可以这样写

        ajax({
            url: url1,
            success: function(data) {
                ajax({
                    url: url2,
                    data: data,
                    success: function() {
                    }
                });
            }
        });

    如果继续下去在回调函数中进行下一步操作,嵌套的层数会越来越多。我们可以进行适当的改进,把回调函数写到外面

        function A() {
            ajax({
                url: url1,
                success: function(data) {
                    B(data);
                }
            });
        }
        function B(data) {
            ajax({
                url: url2,
                success: function(data) {
                    ......
                }
            });
        }

    即使是改写成这样,代码还是不够直观,但是如果有了Promise对象,代码就可以写得非常清晰,一目了然,请看

    new Promise(A).done(B);

    这样函数B就不用写在A的回调中了

    How

    目前的ES标准中还未支持Promise对象,那么我们就自己动手,丰衣足食吧。思路大致是这样的,用2个数组(doneListfailList)分别存储成功时的回调函数队列和失败时的回调队列

    • state: 当前执行状态,有pendingresolvedrejected3种取值

    • done: 向doneList中添加一个成功回调函数

    • fail: 向failList中添加一个失败回调函数

    • then: 分别向doneListfailList中添加回调函数

    • always: 添加一个无论成功还是失败都会调用的回调函数

    • resolve: 将状态更改为resolved,并触发绑定的所有成功的回调函数

    • reject: 将状态更改为rejected,并触发绑定的所有失败的回调函数

    • when: 参数是多个异步或者延迟函数,返回值是一个Promise兑现,当所有函数都执行成功的时候执行该对象的resolve方法,反之执行该对象的reject方法
      下面是我的具体实现过程:

    var Promise = function() {
        this.doneList = [];
        this.failList = [];
        this.state = 'pending';
    };
    
    Promise.prototype = {
        constructor: 'Promise',
        resolve: function() {
            this.state = 'resolved';
            var list = this.doneList;
            for(var i = 0, len = list.length; i < len; i++) {
                list[0].call(this);
                list.shift();
            }
        },
        reject: function() {
            this.state = 'rejected';
            var list = this.failList;
            for(var i = 0, len = list.length; i < len; i++){
                list[0].call(this);
                list.shift();
            }
        },
        done: function(func) {
            if(typeof func === 'function') {
                this.doneList.push(func);
            }
            return this;
        },
        fail: function(func) {
            if(typeof func === 'function') {
                this.failList.push(func);
            }
            return this;
        },
        then: function(doneFn, failFn) {
            this.done(doneFn).fail(failFn);
            return this;
        },
        always: function(fn) {
            this.done(fn).fail(fn);
            return this;
        }
    };
    
    function when() {
        var p = new Promise();
        var success = true;
        var len = arguments.length;
        for(var i = 0; i < len; i++) {
            if(!(arguments[i] instanceof Promise)) {
                return false;
            }
            else {
                arguments[i].always(function() {
                    if(this.state != 'resolved'){
                        success = false;
                    }
                    len--;
                    if(len == 0) {
                        success ? p.resolve() : p.reject();
                    }
                });
            }
        }
        return p;
    }

    Improve

    目前只是实现了Promise的基础功能,但仍然还有无法处理的情况,例如要实现3个或3个以上的异步请求的串行,目前我的Promise没有办法支持new Promise(A).then(B).then(C)这样的形式,jQuery在1.7的版本中为Deferred(Promise)对象实现了pipe函数,可以通过这个函数实现上述功能,代码为$.Deferred(A).pipe(B).then(C),我尝试去读了jQuery这部分的代码,但是没能读懂,希望有大神能够给一些实现思路

  • 相关阅读:
    C#中实现简单的预警提示功能(语音提示与弹窗提示)
    C#中使用SoundPlayer播放音频文件(wav文件)
    Angular中路由的嵌套-父子路由
    Winform中设置ZedGraph的坐标轴的标题和刻度不显示十次幂
    Angular中使用JS实现路由跳转、动态路由传值、get方式传值
    surprise库官方文档分析(二):使用预测算法
    surprise库官方文档分析(一)
    webpack官方文档分析(三):Entry Points详解
    webpack官方文档分析(二):概念
    webpack官方文档分析(一):安装
  • 原文地址:https://www.cnblogs.com/chris-oil/p/5715073.html
Copyright © 2011-2022 走看看