【问题标题】:jquery defered returning too earlyjquery延迟返回太早
【发布时间】:2018-10-11 09:34:39
【问题描述】:

我有以下代码:

$.when(multipleQueries(stateQueries, rowData))
    .then(function (data) {
        //do stuff with data - removed for brevity

multipleQueries 函数如下:

function multipleQueries(queriesToExecute, rowData) {
    var allQueriesMapped = $.Deferred();

    // If a single query has been provided, convert it into an array
    if (Array.isArray(queriesToExecute) === false) {
        queriesToExecute = [].concat(queriesToExecute);
    }

    // Create a function for each region to run the query.
    $.when.apply($, $.map(queriesToExecute, function (query) {

        // Execute the query in the region
        return $.when(executeQuery(query.InstanceInfo, query.Query)).then(function (data) {
            var isDataMapped = $.Deferred();
            var mappedData = [];
            // Perform some data transformation
            $.when.apply($, $.map(data.results, function (value) {
                var properties = value.succinctProperties;
                 //code removed for brevity
                return $.when(mapData(properties)).then(function (mappedRow) {
                    if (mappedRow) {
                        mappedData.push(mappedRow);
                    }
                });
            })).then(function () {
                isDataMapped.resolve({
                    results: mappedData,
                    numItems: mappedData.length
                });
            });
            return isDataMapped.promise();
        }).then(function (data) {
            debugger;
            allQueriesMapped.resolve(data);
        });
    }));

    return allQueriesMapped.promise();
}

我遇到的问题是,我传入了 5 个查询以执行到 multipleQueries 函数,但在运行第一个查询后它正在运行调试器行 - 然后解决 allQueriesMapped deferred,然后它返回到 do包含调用它的数据的东西,但是因为我没有来自我传入的 5 个 queires 的所有数据,所以我没有看到预期的行为 - 我如何设置这些承诺有什么遗漏吗?

注意 - 我尝试将调试器之前的 .then 更改为 .done 但得到相同的行为,并且还尝试将调用代码更改为 .done 如下所示但也得到相同的结果。

$.when(multipleQueries(stateQueries, rowData))
    .done(function (data) {
        //do stuff with data - removed for brevity

** 更新——执行查询函数如下

function executeQuery(instanceInfo, query) {
    return $.ajax({
        url: instanceInfo.Url,
        type: 'GET',
        data: {
            q: query,
            succinct: true
        },
        processData: true
    });
}

【问题讨论】:

  • 看起来它在第一个then 中遇到了您的调试器行,因为then 附加到循环中的每个$.when。即when(A,B,C) { when(a).then(a), when(b).then(b), when(c).then(c) }
  • @T.J.Crowder - 更新了问题以包含该功能
  • then()debugger 处于错误级别。它在第一个map() 内。把它移出那个循环
  • @TJCrowder 不用担心 - 从所有嵌套的 when/then/when/when/maybe then/ 不清楚这是否 答案(只是看起来错了)。

标签: javascript jquery promise jquery-deferred


【解决方案1】:

正如freedomn-m 和charlietfl 指出的那样,这个then 放错地方了(见*** 评论):

function multipleQueries(queriesToExecute, rowData) {
    var allQueriesMapped = $.Deferred();

    // If a single query has been provided, convert it into an array
    if (Array.isArray(queriesToExecute) === false) {
        queriesToExecute = [].concat(queriesToExecute);
    }

    // Create a function for each region to run the query.
    $.when.apply($, $.map(queriesToExecute, function(query) {

        // Execute the query in the region
        return $.when(executeQuery(query.InstanceInfo, query.Query)).then(function(data) {
            var isDataMapped = $.Deferred();
            var mappedData = [];
            // Perform some data transformation
            $.when.apply($, $.map(data.results, function(value) {
                var properties = value.succinctProperties;
                //code removed for brevity
                return $.when(mapData(properties)).then(function(mappedRow) {
                    if (mappedRow) {
                        mappedData.push(mappedRow);
                    }
                });
            })).then(function() {
                isDataMapped.resolve({
                    results: mappedData,
                    numItems: mappedData.length
                });
            });
            return isDataMapped.promise();
        }).then(function(data) {                    // ***
            debugger;                               // ***
            allQueriesMapped.resolve(data);         // ***
        });
    }));

    return allQueriesMapped.promise();
}

它在map里面,什么时候它应该在它外面:

function multipleQueries(queriesToExecute, rowData) {
    var allQueriesMapped = $.Deferred();

    // If a single query has been provided, convert it into an array
    if (Array.isArray(queriesToExecute) === false) {
        queriesToExecute = [].concat(queriesToExecute);
    }

    // Create a function for each region to run the query.
    $.when.apply($, $.map(queriesToExecute, function(query) {

        // Execute the query in the region
        return $.when(executeQuery(query.InstanceInfo, query.Query)).then(function(data) {
            var isDataMapped = $.Deferred();
            var mappedData = [];
            // Perform some data transformation
            $.when.apply($, $.map(data.results, function(value) {
                var properties = value.succinctProperties;
                //code removed for brevity
                return $.when(mapData(properties)).then(function(mappedRow) {
                    if (mappedRow) {
                        mappedData.push(mappedRow);
                    }
                });
            })).then(function() {
                isDataMapped.resolve({
                    results: mappedData,
                    numItems: mappedData.length
                });
            });
            return isDataMapped.promise();
        });
    })).then(function(data) {
        debugger;
        allQueriesMapped.resolve(data);
    });

    return allQueriesMapped.promise();
}

但是其中有很多不必要地使用$.whennew $.Deferred(请参阅*** 1 cmets),您可以更简单地将参数包装在一个数组中(请参阅@ 987654331@评论:

function multipleQueries(queriesToExecute, rowData) {
    // If a single query has been provided, convert it into an array
    if (Array.isArray(queriesToExecute) === false) {
        queriesToExecute = [queriesToExecute]; // *** 2
    }

    // Create a function for each region to run the query.
    return $.when.apply($, $.map(queriesToExecute, function(query) { // *** 1

        // Execute the query in the region
        return executeQuery(query.InstanceInfo, query.Query).then(function(data) { // *** 1
            var mappedData = [];
            // Perform some data transformation
            return $.when.apply($, $.map(data.results, function(value) {
                var properties = value.succinctProperties;
                //code removed for brevity
                return mapData(properties).then(function(mappedRow) { // *** 1
                    if (mappedRow) {
                        mappedData.push(mappedRow);
                    }
                });
            })).then(function() {
                return {
                    results: mappedData,
                    numItems: mappedData.length
                };
            });
        });
    }));
}

当你已经有了一个承诺时,就再也没有必要通过new 创建一个新的承诺了;只需使用then 返回的那个。另外,当你已经有一个承诺时,就没有任何必要使用$.when(thePromise)

您也可能受益于早期切换到内置的 promise 语义而不是 jQuery 的 Deferred

function multipleQueries(queriesToExecute, rowData) {
    // If a single query has been provided, convert it into an array
    if (Array.isArray(queriesToExecute) === false) {
        queriesToExecute = [queriesToExecute];
    }

    // Create a function for each region to run the query.
    return Promise.all(queriesToExecute.map(function(query) {
        // Execute the query in the region
        return executeQuery(query.InstanceInfo, query.Query).then(function(data) {
            return Promise.all(data.results.map(function(value) {
                var properties = value.succinctProperties;
                //code removed for brevity
                return mapData(properties);
            }).then(function(mappedData) {
                mappedData = mappedData.filter(Boolean); // Remove the falsy ones from `mapData`
                return {
                    results: mappedData,
                    numItems: mappedData.length
                };
            });
        });
    }));
}

Promise.all 对于处理承诺数组非常有用。但请确保您使用的是最新的 jQuery,早期版本的 Deferred 无法与真正的 Promise 正确互操作。我不知道(也无法立即找到)何时修复。

【讨论】:

  • 请注意,上面的所有代码都是说明性。它可能需要调整。
  • 感谢您 - 我正在尝试使用您的第二个示例代码更好地重构原始代码。但是,如果我在 return { results: mappedData, numItems: mappedData.length }; 之前放置一个调试器行当我传入 3 个查询时,这会被击中 3 次 - 两次 mappedData 为空,查询中没有结果,一旦它包含数据。但是在调用 $.when(multipleQueries(stateQueries, rowData)) .then(function (data) { 在这里放置一个调试器数据是未定义的,所以它好像没有返回数据
  • @Ctrl_Alt_Defeat:恐怕你只需要调试它。或者,如果您可以模拟各种功能并在演示问题的问题中放置一个可运行的minimal reproducible example,其他人可以提供帮助。要创建一个可运行的示例,请使用[<>] 工具栏按钮; here's how to do one.
  • 谢谢 - 生病继续寻找 - 将 then 从 .map 内部移动到外部会给出相同的结果,但在所有查询运行后无法正确返回数据 - 请继续调试
猜你喜欢
  • 2018-04-28
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 2012-01-11
  • 2016-04-12
  • 2014-06-02
  • 1970-01-01
相关资源
最近更新 更多