首页 > 解决方案 > 如何添加承诺以使 $.when 和 .then 正常运行?

问题描述

我遇到了由异步 Javascript 执行引起的问题。我正在尝试使用函数设置变量的值,然后立即在函数调用中使用该变量。我想实现 JQuery .when 和 .then 来解决这个问题,但是我在如何实现 .then 知道何时开始执行所需的承诺方面遇到了麻烦。

这是我所拥有的:

function addSerialNumber(item_id) {
    var serialNumberList;
    var serialNumber = $("serial-number").val();

    $.when(serialNumberList = addSerialFunc(item_id, serialNumber))
    .then(alert("Serial number successfully added."), 
        insertTransaction(item_id, serialNumberList));
}

function addSerialFunc(item_id, serialNumber) {
    var serialNumberList = new Array();

    $.ajax({
        type: "post",
        url: "someRandom.jsp",
        data: {wsFunction: "Insert", item_id: item_id, serialNumber: serialNumber},
        async: false
    }).done(function(xml){
        $(xml).find("Item").each(function() {
            insert_id = ($(this).find("SendBack_CD").text());

            if (!runError(insert_id, item_id)) {
                //Fail
            } else {
                //Success
                serialNumberList.push(insert_id);
            }
        })
    }).fail(function(jqXHR, textStatus, errorThrown) {
        console.log("Error occured! Type: " + textStatus + " HTTP Error Thrown: " + errorThrown);
    });

    return serialNumberList;
}

我正在尝试通过调用 addSerialFunc() 创建 serialNumberList,然后使用 serialNumberList 作为 insertTransaction() 的参数。这有时有效,但我间歇性地得到

Uncaught TypeError: Cannot read property 'substring' of undefined

因为它试图在 addSerialFunc() 填充 serialNumberList 之前执行 insertTransaction()。

如何在 addSerialFunc() 中实现承诺,以便 .then 知道何时开始执行?

标签: javascriptjquerypromise

解决方案


几个问题:

  • addSerialFunc您同步返回一个值,但它只会在以后填充,当响应来自异步 ajax 调用时。相反,您应该返回$.ajax.

  • alert立即调用,而不是将回调函数传递给then.

  • 您将第二个参数传递给then,由于与前一点相同的原因,这又不是一个函数。而且,第二个参数应该是当 Promise 被拒绝时的函数。

所以,这应该会更好——它假设 jQuery 版本 3.x:

function addSerialNumber(item_id) {
    var serialNumberList;
    var serialNumber = $("serial-number").val();

    // *** $.when is not needed
    addSerialFunc(item_id, serialNumber) // *** start with the returned promise
    .then(function (serialNumberList) { // pass a function(!), which gets the value as argument
        alert("Serial number successfully added."); 
        insertTransaction(item_id, serialNumberList);
    }).catch(function (err) { // better to also have a `catch` call here
        console.log(err);
        console.log("because of error, no transaction is inserted");
    });
}

function addSerialFunc(item_id, serialNumber) {    
    return $.ajax({
//  ^^^^^^
        type: "post",
        url: "someRandom.jsp",
        data: {wsFunction: "Insert", item_id: item_id, serialNumber: serialNumber}
        /* drop the `async` property */
    }).then(function(xml){
 //    ^^^^
        var serialNumberList = new Array(); // *** define here
        $(xml).find("Item").each(function() {
            var insert_id = ($(this).find("SendBack_CD").text());
    //      ^^^^ make sure to always define the scope of your variables!
            if (!runError(insert_id, item_id)) {
                //Fail
                throw "Some error occurred"; // *** adapt message here
                ^^^^^^
            } else {
                //Success
                serialNumberList.push(insert_id);
            }
        });
        return serialNumberList; // *** return!!!!
    }).catch(function(jqXHR, textStatus, errorThrown) {
 //    ^^^^^
        console.log("Error occured! Type: " + textStatus + " HTTP Error Thrown: " + errorThrown);
        throw errorThrown; // *** cascade the error
    });
}

推荐阅读