Promise的簡單實現

ES6 原生提供了 Promise 對象,大大簡化了 callback 的代碼維護難度。使用promise對象以後能夠使用一種鏈式調用的方式來組織代碼;讓代碼更加的直觀。ajax

若是想在老瀏覽器中使用 Promise,須要使用第三方庫。實際實現遠離並不複雜,僅須要十幾行代碼,就能實現相似的效果(實際仍是有點區別的)。promise

// 簡單的實現 Promise 的函數
// 原文地址:http://www.miaoqiyuan.cn/p/promise
var PromiseDemo = function(fun, _status_code){
    
    this._status_code = _status_code || 'status';
    
    //執行
    this.run = function(){
        this._result = fun.call(this, fun);
        
        //若是執行函數會 同步 返回結果,則調用callback。
        if( !! this._result ){
            return this.callback();
        };
    };
    
    //回調函數,若是不是當即返回結果,須要手動調用
    this.callback = function(_result){
        
        //異部調用時,傳入執行結果
        if( !!_result ){
            this._result = _result;
        }
        
        //如過狀態不是 object
        this._result = this._result || {};
        
        //若是沒有指定 【返回狀態】 值,若是沒有,則使用 status
        this._status = this._result[this._status_code] || 'fail';
        
        /*
            若是 【返回狀態】 已經定義了 回調函數,調用本狀態回調函數
            若是 【返回狀態】 沒有定義,則調用 _default 函數
            若是 【返回狀態】 沒有定義,而且沒有調用 _default 函數,拋出異常
        */
        this._callback = this[this._status] || this._default || function(){ throw new Error("Undefined " + this._status); };
        return this._callback.call(this);
    };
    
    //then判斷
    this.then = function(_status, callback){
        if( typeof _status == "function" ){
            
            //沒有指定狀態
            callback = _status;
            if( !('success' in this) ){
                
                //沒有 success,則將 callback 設置爲 success 狀態的回調函數
                _status = 'success';
                
            }else if( !('fail' in this) ){
                
                //沒有 fail,則將 callback 設置爲 fail 狀態的回調函數
                _status = 'fail';
                
            }else{
                
                // 若是 success 和 fail 已經設置,不管調用多少次,都是 默認狀態 的回調函數
                _status = '_default';
                
            };
        };
        
        //設置 【返回狀態】 的回調函數
        this[_status] = callback;
        
        //鏈式操做
        return this;
    };
    
    //鏈式操做
    return this;
}
就這麼幾行代碼,就實現了簡單的 Promise。爲了方便測試,寫成函數
var PromiseTest = function(fun, _status_code, _default){
    if( typeof _status_code == "function" ){
        _default = _status_code;
        _status_code = undefined;
    }
    var pTest = new PromiseDemo(fun, _status_code);
    
    pTest.then(function(){
        console.log("Success!");
        console.log(this._result);
    });
    
    pTest.then(function(){
        console.log("Fail!");
        console.log(this._result);
    });
    
    if( typeof _default == "function"){
        pTest.then(_default);
    };

    return pTest;
}
下面的代碼用於測試效果:

返回成功狀態
PromiseTest(function(){
    return { status: 'success'};
}).run();
/*
    Success!
    Object {status: "success"}
*/
返回失敗狀態
PromiseTest(function(){
    return { status: 'fail'};
}).run();
/*
    Fail!
    Object {status: "fail"}
*/
返回其餘狀態,沒有定義,拋出異常
PromiseTest(function(){
    return { status: 'other'};
}).run();
/*
    Uncaught Error: Undefined other(…)
*/
修改 【返回狀態】 參數,返回成功狀態
PromiseTest(function(){
    return { status: 'other', code : 'success'};
}, "code").run();
/*
    Success!
    Object {status: "other", code: "success"}
*/
增長默認值函數,全部未定義的狀態,都是用此回調函數
PromiseTest(function(){
    return { status: 'other'};
}, function(){
    console.log("Other");
}).run();
/*
    Other
*/
自定義狀態值,返回 nicai 狀態
PromiseTest(function(){
    return { status: 'nicai'};
}).then('wocai', function(){
    console.log("Wocai");
}).then('nicai', function(){
    console.log("Nicai");
}).run();
/*
    Nicai
*/
同步調用有返回值
PromiseTest(function(){
    return { status: 'nicai', value : "abc"};
}).then('nicai', function(){
    console.log("Nicai");
    return this._result.value;
}).run() == 'abc';
/*
    Nicai
    true
*/
異部調用測試:setTimeout
PromiseTest(function(){
    setTimeout(
        (function(){
            this.callback({
                status : 'success'
            });
        }).bind(this),    //必須bind,不然函數內部的 this == window
    1000);
}).run();
/*
    Success!
    Object {status: "success"}
*/
異部調用測試:Ajax
PromiseTest(function(){
    $.ajax({
         type    : "POST",
        url        : "/services/PinYin",
        data    : {input:'測試'},
        success    : (function(result){
            this.callback({
                status : 'success',
                result : result
            });
        }).bind(this),    //經過 bind 改變 this 的指向
        error    : (function(){
            this.callback();
        }).bind(this)
    });
}).run();

//成功
/*
    Success!
    Object {status: "success", result: "Ceshi"}
*/

//失敗
/*
    Fail!
    Object {}
*/
異部調用測試:若是須要用 this 訪問 jQuery 的 ajax 對象
PromiseTest(function(){
    var me = this;    //在本函數內,用能夠 me 指向 this(PromiseDemo的實例);
    $.ajax({
         type    : "POST",
        url        : "/services/PinYin",
        data    : {input:'測試'},
        success    : (function(result){
            me.callback({
                status : 'success',
                result : result
            });
        }),
        error    : (function(){
            me.callback();
        })
    });
}).run();
相關文章
相關標籤/搜索