5

我有一个与本地服务连接的网站,该服务管理带有密码键盘的读卡器。使用此设备可以完成许多不同的操作。下面是其中之一的示例:

  1. 锁定设备
  2. 询问 PIN 码
  3. 释放装置

之前我曾经将回调相互链接,但现在,因为有新的操作,也使用“锁定”和“释放”等方法,我需要更改我的代码,以便第 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
        });
    }
};
4

5 回答 5

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);
    },

演示

完整代码:

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();
于 2013-07-25T12:02:32.267 回答
1

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

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 并返回它。一旦您收到超时、错误或任何结果,您就会调用 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 上调用拒绝时,控制流将传递给 catch 函数,从而大大简化了编程。

库中有许多附加功能和特性,因此您将能够处理并行运行的步骤等。查看文档,这是非常值得的。

于 2013-07-25T22:10:16.260 回答
1

阅读这个 jquery 文档页面:

http://api.jquery.com/category/callbacks-object/

http://api.jquery.com/category/deferred-object/

于 2013-07-26T13:39:10.863 回答
1

尝试async: false使用您的 Ajax 调用。这首先完成您的 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
    });
}
于 2013-07-30T16:46:50.573 回答
-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);
        }
        });            
于 2013-07-31T14:50:02.220 回答