如何添加承诺以使$ .when和.then正常返回?

时间:2019-06-17 19:30:35

标签: javascript jquery promise

我遇到了由异步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知道何时开始执行?

1 个答案:

答案 0 :(得分:1)

几个问题:

  • addSerialFunc中,您将同步返回一个值,但是只有在异步ajax调用返回响应时,才会稍后填充该值。相反,您应该返回由$.ajax返回的承诺

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

  • 您将第二个参数传递给then,由于与上一点相同的原因,该参数也不是函数。但是,第二个参数应该是承诺何时被拒绝的函数。

因此,这应该更好用-假定使用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
    });
}