简体   繁体   English

递延,承诺和Ajax的顺序不正确

[英]Deferred, Promises, and Ajax not going in correct order

I'm trying to set up a loop of Ajax calls and a function that runs after all the Ajax calls have resolved. 我试图建立一个Ajax调用循环,并在所有Ajax调用解决后运行一个函数。 I read through a bunch of SO questions on this problem and thought I was able to apply it to my code, but it isn't working and I can't for the life of me figure out why. 我通读了许多关于此问题的SO问题,并认为我可以将其应用于代码中,但是它无法正常工作,我一生都无法找出原因。

Here's the JS code. 这是JS代码。 The map function runs 10 times FYI. map function运行时间是FYI的10倍。

function addData(data) {
    var deferreds = [];
    $.map(data, function(job) {
        deferreds.push(addLocation(job));
    });

    console.log(deferreds);
    $.when.apply($, deferreds).then(mapData(data));
}

function addLocation(job) {
    var dfd = $.Deferred(),
        url = url;

    console.log('in the addLocation function, outside the ajax call');
    $.ajax({
        url: url,
        dataType: 'jsonp',
        jsonp: 'json_callback'
    }).done(function(location) {
        job.lnglat = [parseFloat(location[0].lon), parseFloat(location[0].lat)];
        console.log('resolved location');
        dfd.resolve();
    });

    return dfd.promise();
}

function mapData(data) {
    console.log('in the mapData function');
    console.log(data);
    var point = svg.selectAll('points')
        .data(data);

    point.exit().remove();
    point.enter().append('circle')
        .attr('r', 2.5);

    point
        .attr('cx', function(d) {
            console.log(d);   //shows d and has the lnglat but I think that is due to the developer tools reading the final result, not the result at the time
            console.log(d.lnglat);   // this gives undefined
            console.log(d.lnglat[0]); // this gives an error as it hasn't been defined
            console.log(projection(d.lnglat[0]));
            return projection(d.lnglat[0])[0];
        })
        .attr('cy', function(d) {
            return projection(d.lnglat[1])[1];
        });
}

The Chrome Developer tools reports the following order: Chrome开发人员工具报告以下顺序:

in the addLocation function, outside the ajax call  //x10
[Object, object...] //this is the object list of deferred objects, there are 10 of them
in the mapData function
[Object, object..] //this is the object list of data from the mapData function
Object > ... //this is the d object in the mapData function > point anonymous function
undefined // this is the result of d.lnglat
Uncaught typeError ... // this is the result of d.lnglat[0] which doesn't exist yet
resolvedLocation //x10 this should be a lot higher right?

So I want the resolvedLocation console.log to run prior to the in the mapData function to run and I thought I had set it up that way, but it obviously isn't working. 所以我想让in the mapData function resolvedLocation console.log in the mapData function运行之前运行,我想我已经用这种方式进行了设置,但显然不起作用。 What am I missing? 我想念什么?

As adeneo said in his comment, the problem here is the imidiate invocation of mapData in 正如adeneo在他的评论中所说,这里的问题是在

$.when.apply($, deferreds).then(mapData(data)) $ .when.apply($,deferreds).then(mapData(data))

To solve this you need to use bind to keep most of you solution intact (and not change it much). 为了解决这个问题,您需要使用bind来使您的大多数解决方案保持完整(并且不要对其进行太多更改)。 This should work: 这应该工作:

$.when.apply($, deferreds).then(mapData.bind(this, data)) $ .when.apply($,deferreds).then(mapData.bind(this,data))

The bind does not delay the invocation of the function. 绑定不会延迟该函数的调用。 It binds the data argument to the invocation of the function, so when 'then' function invokes mapData, it does so with 'data' as its argument, and that happens only after all promises are resolved. 它将数据参数绑定到函数的调用上,因此,当“ then”函数调用mapData时,它将以“ data”作为参数来进行调用,并且仅在所有promise都解决后才会发生。

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

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