前端通讯:ajax设计方案(五)--- 集成promise规范,更优雅的书写代码(改迭代已做废,移步迭代10)

 该迭代已做废,最新的请移步这里:http://www.javashuo.com/article/p-ozwheqin-w.htmlhtml

      距离上一篇博客书写,又过去了大概几个月了,这段时间暂时离开了这个行业,让大脑休息一下。一我的旅行,一我的休息,正好也去完成一个目标 --- 拥有本身的驾照。固然,也把本身晒的黑漆马虎的。不过这一段时间虽然在技术上没有学太多东西,可是在心态上给了本身一个沉淀的机会,感受本身变得更加沉稳和成熟,感受这就是本身须要找到的本身,回归自我。好了,废话很少说了,虽然技术上没有学一些新的东西,可是欠的东西仍是要补回来的。正如这篇博客,前端Promise规范的实现与ajax技术的集成,当时github上一个用户提的,既然写了ajax,那么Promise的规范,更优雅的操做异步也应该有的,当时记下了,如今补回来。回归正题,下面介绍一些概念。前端

  • Promise   ES6中最重要的特性之一,就是表明了将来某个将要发生的事件(一般是一个异步操做)。它的好处在于,有了Promise对象,就能够将异步操做以同步操做的流程表达出来,避免了层层嵌套的回调函数。
  • js对象的继承和传递  在js中是没有所谓的继承概念的,继承一般是指后台面向对象编程中对象之间的复用。由于js被叫作脚本语言,因此没有这个概念,可是在js中均可以模拟实现的(apply,call,prototype)。其实说通俗点所谓的继承就是做用域的传递。
  • ajax和promise的缘分  由于ajax是一个异步的请求(虽然也可使用同步),而promise这个状态机也正好能够处理异步操做。二者的相结合的产物,将是一个优雅而又快捷的产物,这个将在后面的介绍中展示。

 

工具准备:nginx

    1. 前端代码,本身实现的promise规范代码,以及集成现有es6规范的代码。git

    2. nginx服务器,作分离,反向代理后台代码es6

    3. IIS服务器,部署后台请求(模拟通常请求和高延迟请求)github

    4. 各大兼容和不兼容promise的浏览器(作测试)ajax

 

前端Promise代码实现:chrome

/**
 * Created by gerry.zhong on 2017/6/21.
 */
var Promise = function(fn){
    var promise = this;
    //状态机的状态
    var PROMISESTATE = {
        PENDING : 0 ,
        FULFILLED : 1 ,
        REJECTED : 2
    };
    //存储当前变量的回调函数和标记对象为promise
    promise._fullCalll =[],promise._rejCall = [];promise._name = "promise";
    //执行过程当中的状态变化(初始化状态为默认状态)
    var _state =  PROMISESTATE.PENDING;
    //回调函数的参数
    var _value = undefined;

    //状态变动
    function setState(stateT,valueT){
        var promise = this;
        _state = stateT;
        _value = valueT;
        handleFun.call(promise);  //传递做用域,而且执行回调函数
    };

    //根据状态处理回调
    function handleFun(){
        var promise = this,isThen;

        if (_state === PROMISESTATE.FULFILLED &&
            typeof promise._fullCalll[0] === 'function') {
            isThen = promise._fullCalll[0](_value);
        };
        if (_state === PROMISESTATE.REJECTED &&
            typeof promise._rejCall[0] === 'function') {
            isThen = promise._rejCall[0](_value);
        };
        //对因而否能够继续进行then作判断
        //  1. 不可then的,直接return结束(条件:无返回值、返回值不是promise对象的)
        //  2. 对于能够then的,将then的回调进行处理,而后对象之间传递。
        if (isThen === undefined || !(typeof isThen === 'object' && isThen._name === 'promise')) return;

        promise._fullCalll.shift(); promise._rejCall.shift();      //清除当前对象使用过的对调
        isThen._fullCalll =promise._fullCalll;isThen._rejCall = promise._rejCall;  //将剩下的回调传递到下一个对象
    };

    //promimse入口
    function doResolve(fn){
        var promise = this;
        fn(function(param) {
            setState.call(promise,PROMISESTATE.FULFILLED,param);
        }, function(reason) {
            setState.call(promise,PROMISESTATE.REJECTED,reason);
        });
    };

    //函数then,处理回调,返回对象保证链式调用
    this.then = function(onFulfilled,onRejected) {
        this._fullCalll.push(onFulfilled);
        this._rejCall.push(onRejected);
        return this;
    }

    doResolve.call(promise,fn);
}

具体思路以下:编程

 

解决浏览器的差别性和兼容性代码后端

if (!window.Promise) tool.createPromise();  //保证浏览器的兼容性

 

tool.createPromise代码

//若是浏览器不支持Promise特性,将用简易的promise代替(IE11-都不支持ES6 Promise)
        createPromise:function(){
            var newPromise = function(fn){
                var promise = this;
                //状态机的状态
                var PROMISESTATE = {
                    PENDING : 0 ,
                    FULFILLED : 1 ,
                    REJECTED : 2
                };
                //存储当前变量的回调函数和标记对象为promise
                promise._fullCalll =[],promise._rejCall = [];promise._name = "promise";
                //执行过程当中的状态变化(初始化状态为默认状态)
                var _state =  PROMISESTATE.PENDING;
                //回调函数的参数
                var _value = undefined;

                //状态变动
                function setState(stateT,valueT){
                    var promise = this;
                    _state = stateT;
                    _value = valueT;
                    handleFun.call(promise);  //传递做用域,而且执行回调函数
                };

                //根据状态处理回调
                function handleFun(){
                    var promise = this,isThen;

                    if (_state === PROMISESTATE.FULFILLED &&
                        typeof promise._fullCalll[0] === 'function') {
                        isThen = promise._fullCalll[0](_value);
                    };
                    if (_state === PROMISESTATE.REJECTED &&
                        typeof promise._rejCall[0] === 'function') {
                        isThen = promise._rejCall[0](_value);
                    };
                    //对因而否能够继续进行then作判断
                    //  1. 不可then的,直接return结束(条件:无返回值、返回值不是promise对象的)
                    //  2. 对于能够then的,将then的回调进行处理,而后对象之间传递。
                    if (isThen === undefined || !(typeof isThen === 'object' && isThen._name === 'promise')) return;

                    promise._fullCalll.shift(); promise._rejCall.shift();      //清除当前对象使用过的对调
                    isThen._fullCalll =promise._fullCalll;isThen._rejCall = promise._rejCall;  //将剩下的回调传递到下一个对象
                };

                //promimse入口
                function doResolve(fn){
                    var promise = this;
                    fn(function(param) {
                        setState.call(promise,PROMISESTATE.FULFILLED,param);
                    }, function(reason) {
                        setState.call(promise,PROMISESTATE.REJECTED,reason);
                    });
                };

                //函数then,处理回调,返回对象保证链式调用
                this.then = function(onFulfilled,onRejected) {
                    this._fullCalll.push(onFulfilled);
                    this._rejCall.push(onRejected);
                    return this;
                }

                doResolve.call(promise,fn);
            };
            window.Promise = newPromise;
        },

这样就保证了,无论在兼容和不兼容Promise的浏览器中,均可以使用Promise,优雅的来操做异步了。

 

ajax集成proise代码(默认只开放了post和get方法,其余可本身拓展)

     //集成promise的ajax请求(默认设置post和get请求,若有其余需求,可本身拓展)
        promiseAjax:function (url,data,type){
            if (!window.Promise) tool.createPromise();  //保证浏览器的兼容性
            return new Promise(function(resolve, reject){
                if (type === undefined) ajax.post(url,data,resolve,reject);
                else ajax.get(url,data,resolve,reject);
            });
        },

 

测试环节

  对于网上不少人写的Promise代码仔细观摩和研究,发现不少问题。

    a. 对于并发Promise,会出现异步错乱,发起者和接受者错乱

    b. 对于多then的状况,异步响应的不肯定(高低延迟),错乱。

    c. Promise代码实现的复杂性,多繁琐,难理解,思路不明确。

   针对以上问题,进行重要测试。

 

测试前端代码

    ajax.promiseAjax("api/ajax/postReq/",{"name":"q","age": 2})
            .then(function(value){
                console.log("通常请求q"+value);
                return ajax.promiseAjax("api/ajax/postReqSleep/",{"name":"w","age": 2});
            })
            .then(function(value){
                console.log("高延迟请求w:"+value);
                return ajax.promiseAjax("api/ajax/postReq/",{"name":"r","age": 2});
            })
            .then(function(value){
                console.log("通常请求r:"+value);
            });


    ajax.promiseAjax("api/ajax/postReqSleep/",{"name":"q1","age": 2})
            .then(function(value){
                console.log("高延迟请求q1"+value);
                return ajax.promiseAjax("api/ajax/postReqSleep/",{"name":"w2","age": 2});
            })
            .then(function(value){
                console.log("高延迟请求w2:"+value);
                return ajax.promiseAjax("api/ajax/postReq/",{"name":"r3","age": 2});
            })
            .then(function(value){
                console.log("通常请求r3:"+value);
            });

后端模拟延迟请求代码(C#)

        [Route("postReqSleep")]
        public string postRequestTSleep([FromBody]Param param)
        {
            Thread.Sleep(5000);   //挂起5s 作延迟
            String result = "post请求成功:" + param.name + "-" + param.age;
            return result;
        }

 

 

测试结果:

  chrome

  ie8-11

  edge

  firefox

  360浏览器

  safair

 

  代码已集成github:https://github.com/GerryIsWarrior/ajax     点颗星星是我最大的鼓励,有什么问题能够博客、邮箱、github上留言

 还有最重要的一点,若是有问题欢迎指出来,我在github上维护这个库,这段时间专一于前端的通讯技术的研究,ajax基本完成,立刻进入SSE推送技术研究状态

 

研究Promise这个内容,研究和参考了不少别人的代码,从高别人的代码中看到了各类问题,而后在本身代码中测试发现和改正。因此没有什么是绝对正确的,我写的可能也有问题,但愿你们在研究和发展的基础上一块儿改进。毕竟对于前端来讲,技术更新太快,ES5 ES6等等一层接一层。仍是那句老话,革命还没有成功,同志仍需努力,我和大家同在。

 

立刻又要回去从新找工做了,但愿能够找到如意的工做,毕竟为了错开金三银四,但愿一切都会好起来。一块儿加油吧。

相关文章
相关标签/搜索