如何使用jQuery管理链式AJAX调用

时间:2013-07-23 08:44:44

标签: jquery ajax asynchronous callback promise

我的网站连接本地服务,该服务使用PIN Pad管理CardReader。使用此设备可以完成许多不同的操作。以下是其中一个例子:

  1. 锁定设备
  2. 询问密码
  3. 发布设备
  4. 之前我曾经在彼此之间链接回调,但现在,因为有新的操作,也使用像“lock”和“release”这样的方法,我需要更改我的代码,以便第1步的代码3是可重复使用的。

    我一直试图用jQuery承诺来解决这个问题,但我对此很新,而且我还没有真正弄清楚它们是如何工作的。有人可以帮我一把吗?

    这是我现在使用的代码示例。我已从函数内部删除了业务逻辑,以简化示例:

    var CardReader = {
    
        ////////////////////
        // Different possible messages to the Card Reader
        ////////////////////
    
        lockDevice: function() {
            this.makeAjaxCall("GET", "/LockDevice", this.lockDeviceCallback);
        },
    
        getPin: function() {
            this.makeAjaxCall("POST", "/getPin", this.getPinCallback);
        },
    
        releaseDevice: function() {
            this.makeAjaxCall("POST", "/Release", this.releaseDeviceCallback);
        },
    
        //////////////////
        // Callbacks for each message to the Card Reader
        //////////////////
    
        lockDeviceCallback: function(jqXHR, textStatus) {
            if (textStatus !== "success") { return; }
            this.getCardLogin();
        },
    
        getCardLoginCallback: function(jqXHR, textStatus) {
            if (textStatus !== "success") { return; }
            this.releaseDevice();
        },
    
        releaseDeviceCallback: function(jqXHR, textStatus) {
            if (textStatus !== "success") { return; }
            //End
        },
    
        ////////////////
        // Other methods
        ////////////////
    
        init: function() {
            // UI BIndings
            $(#button).on("click", this.logIn.bind(this));
        },
    
        logIn: function() {
            this.lockDevice();
        },
    
        makeAjaxCall: function(callType,  resource, callbackMethod) {
    
            $.ajax({
                type       : callType,
                url        : "http://localhost:1337" + resource,
                cache      : false,
                dataType   : "json",
                contentType: "application/json",
                context    : this,
                complete   : callbackMethod
            });
        }
    };
    

5 个答案:

答案 0 :(得分:1)

这可以满足您的需求,即使我不确定在这里完全理解您的问题。

这里的重点似乎是保持对ajax方法回调的顺序。你可以这样做:

创建这些方法:

 _nextCall: function (deferreds, method) {
        if (deferreds.length) this._when(deferreds, method);
        else console.log(method + " SUCCESS");
    },
    _when: function (calls, method) {
        var $promise = $.when(this[calls[0]]())
        $promise.then(function () {
            calls.splice(0, 1);
            this._nextCall(calls, method);
        }, function () {
            console.log(method + " FAILED on: " + calls[0]);
        });
    },

像那样使用它:

logIn: function logIn() {
        var calls = ["lockDevice", "getCardLogin", "releaseDevice"];
        this._when(calls, arguments.callee.name);
    },
    getPinOnly: function getPinOnly() {
        var calls = ["getPin"];
        this._when(calls, arguments.callee.name);
    },

DEMO

完整代码:

var CardReader = {

    ////////////////////
    // Different possible messages to the Card Reader
    ////////////////////

    lockDevice: function () {
        return this.makeAjaxCall("GET", "/LockDevice", this.lockDeviceCallback);
    },
    getCardLogin: function () {
        return this.makeAjaxCall("POST", "/getCardLogin", this.getCardLoginCallback);
    },
    getPin: function () {
        return this.makeAjaxCall("POST", "/getPin", this.getPinCallback);
    },

    releaseDevice: function () {
        return this.makeAjaxCall("POST", "/Release", this.releaseDeviceCallback);
    },

    //////////////////
    // Callbacks for each message to the Card Reader
    //////////////////

    lockDeviceCallback: function (jqXHR, textStatus) {
        console.log("lockDeviceCallback");
        if (textStatus !== "success") {
            return;
        }
    },

    getCardLoginCallback: function (jqXHR, textStatus) {
        console.log("getCardLoginCallback");
        if (textStatus !== "success") {
            return;
        }
    },
    getPinCallback: function (jqXHR, textStatus) {
        console.log("getPinCallback");
        if (textStatus !== "success") {
            return;
        }
    },

    releaseDeviceCallback: function (jqXHR, textStatus) {
        console.log("releaseDeviceCallback");
        if (textStatus !== "success") {
            return;
        }
        //End
    },

    ////////////////
    // Other methods
    ////////////////

    init: function () {
        // UI BIndings
        $('#btn_login').on("click", $.proxy(this.logIn, this));
        $('#btn_getPinCallback').on("click", $.proxy(this.getPinOnly, this));
    },
    _nextCall: function (deferreds, method) {
        if (deferreds.length) this._when(deferreds, method);
        else console.log(method + " SUCCESS");
    },
    _when: function (calls, method) {
        var $promise = $.when(this[calls[0]]())
        $promise.then(function () {
            calls.splice(0, 1);
            this._nextCall(calls, method);
        }, function () {
            console.log(method + " FAILED on: " + calls[0]);
        });
    },
    logIn: function logIn() {
        var calls = ["lockDevice", "getCardLogin", "releaseDevice"];
        this._when(calls, arguments.callee.name);
    },
    getPinOnly: function getPinOnly() {
        var calls = ["getPin"];
        this._when(calls, arguments.callee.name);
    },

    makeAjaxCall: function (callType, resource, callbackMethod) {

        return $.ajax({
            type: callType,
            url: "/echo/json", // + resource,
            cache: false,
            dataType: "json",
            contentType: "application/json",
            context: this,
            success: callbackMethod
        });
    }
};

CardReader.init();

答案 1 :(得分:1)

使用功能更全面的promises库。看看:https://github.com/kriskowal/q 值得花一点时间来理解,因为它极大地改善了代码的风格和可读性。基本上你可以编写每个业务函数,因此它返回一个promise,如下所示: -

function myBusinessFunction(params) {
    var deferred = Q.defer();
    ....
    doSomeAsyncFunction(params,function(error,result) {
        if (error) {
           deferred.reject(new Error(error)); //pass the error on
        } else {
           deferred.resolve(result);
        }
    });
    return deferred.promise;
}

所以这里发生的是你创建一个函数的每个异步操作,在里面创建一个延迟并返回它。一旦出现超时或错误或任何结果,您就会调用deferred.reject或deferred.resolve。

通过添加代码,您可以避免回调地狱,其中有许多嵌套函数,并创建如下所示的整体算法代码: -

Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
    // Do something with value4
})
.catch(function (error) {
    // Handle any error from all above steps
})
.done();

这非常类似于try ... catch程序样式编程,它非常熟悉,但实际上是在处理异步进程。当你在promise上调用reject时,控制流将传递给catch函数,大大简化了编程。

库中还有许多其他功能和特性,因此您可以并行处理运行步骤等。查看文档是值得的。

答案 2 :(得分:1)

答案 3 :(得分:1)

使用Ajax调用尝试async: false。这首先完成Ajax调用,然后执行其他语句。

makeAjaxCall:function(callType,resource,callbackMethod){

    $.ajax({
        type       : callType,
        url        : "http://localhost:1337" + resource,
        cache      : false,
        dataType   : "json",
        contentType: "application/json",
        context    : this,
        async :false,
        complete   : callbackMethod
    });
}

答案 4 :(得分:-1)

       jQuery.support.cors = true;

        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            datatype: "json",               
            async :false,
            url: "http://yourHost:portnumeber/ServiceName/LockDevice",
            success:
        lockDeviceCallback,
            error:
        function (XmlHttpRequest, textStatus, errorThrown) {
            errorHandler(XMLHttpRequest);
        }
        });            
相关问题