前端通訊: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等等一層接一層。仍是那句老話,革命還沒有成功,同志仍需努力,我和大家同在。

 

立刻又要回去從新找工做了,但願能夠找到如意的工做,畢竟爲了錯開金三銀四,但願一切都會好起來。一塊兒加油吧。

相關文章
相關標籤/搜索