ES6 原生提供了 Promise 对象,大大简化了 callback 的代码维护难度。使用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();

mqycn
2.1k 声望23 粉丝

野生程序员,成长中的全栈开发者