简体   繁体   English

jQuery推迟返回太早

[英]jquery defered returning too early

I have the following code: 我有以下代码:

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

The multipleQueries function is below: 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();
}

The issue I am having is that I am passing in say 5 queries to excute to the multipleQueries function but it is hitting the debugger line after running the first query - this is then resolving the allQueriesMapped deferred and then it returns to the do stuff with data where it was called from but because I dont have all the data from the 5 queires I passed in I am not seeing the expected behaviour - is there something missing with how I have set up these promises? 我遇到的问题是我传入了5个查询以执行对multipleQueries函数的操作,但是在运行第一个查询后却击中了调试器行-然后解决了延迟的allQueriesMapped问题,然后将其返回给处理数据的对象它是从哪里调用的,但是因为我没有传入的5个查询的所有数据,所以我看不到预期的行为-我如何建立这些诺言?

Note - I tried changing the .then before the debugger to .done but getting same behavior and also tried to change the calling code to .done as below but getting the same as well. 注意-我尝试将调试器之前的.then更改为.done,但得到相同的行为,还尝试将调用代码更改为.done,如下所示,但也得到相同的效果。

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

** Update - the execute query function is below **更新-执行查询功能在下面

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

As freedomn-m and charlietfl pointed out, this then is in the wrong place (see *** comment): 作为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();
}

It's inside the map , when it should be outside it: 它在map ,应该在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();
}

But there's a lot of unnecessary use of $.when and new $.Deferred in there (see *** 1 comments), and you can wrap your parameter in an array much more simply (see *** 2 comment: 但是,有很多不必要使用的$.whennew $.Deferred在那里(见*** 1意见),你可以在一个阵列更加简单包装您的参数(见*** 2评论:

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

When you have a promise already, there's never any need to create a new one via new ; 当您已经有了一个承诺时,就不需要通过new创建一个新的承诺了; just use the one returned by then . 只需使用then返回的then Also, when you already have a promise, there's never any need to use $.when(thePromise) . 另外,当您已经有了承诺时,就不需要使用$.when(thePromise)

You might also benefit from switching to built-in promise semantics instead of jQuery's Deferred early: 您还可以从切换到内置的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 is very useful for dealing with arrays of promises. Promise.all对于处理承诺数组非常有用。 But be sure you're using an up-to-date jQuery, earlier versions of Deferred didn't interoperate properly with real promises. 但是请确保您使用的是最新的jQuery,但Deferred的早期版本无法与真正的Promise正确地互操作。 I don't know (and can't immediately find) when that was fixed. 我不知道(并且无法立即找到)何时解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM