jquery暂停循环直到满足全局条件

时间:2010-11-08 12:08:08

标签: jquery ajax

好吧,我有一个ajax调用,可以重现json对象。

我想要做的事情的想法是获取标记的所有记录的列表,并对地理编码进行反向查找并保存回数据库,但是作为批处理

我想遍历数据,然后执行额外的ajax调用(将对数据进行地理编码),然后执行另一个ajax调用以保存到数据库。

问题出在我的for循环中,一切运行得太快,调用和浏览器崩溃之间没有暂停,或者保存到数据库函数会添加错误的数据。

$('#geo_batch').click(function (){
            var ajax_load = "<label><img src='/images/icons/loadinfo.gif' alt='saving location...' /> Loading data...</label>";
            $("#batch_detail").html(ajax_load);
            $('#batch_buttons').hide();
            saveall = true;
            var form = $("form"); //Grab the form element from the DOM 
            //alert(form.serialize());
            var mydata = form.serialize();
            $.ajax({  
                type: "POST",  
                url: 'geo_getupdate_list.php', 
                data: mydata,  
                dataType: 'json',
                success: function(dat) {
                    processbatch(dat);// process the returned data
                }, 
                error: function(dat) { //Triggered if an error communicating with server   
                     //alert('fail');
                     $("#batch_detail").html('<label>There was an error: '+dat+'<label>');  
                     $('#batch_buttons').show();
                }
            });  
            return false; //Ignore the default behavior of the button click  
        });

过程数据功能

function processbatch(dat){
            // Cache the batch_detail element
            $("#batch_detail").html('<label>Locations have been retrieved:<br>' + dat + '<label>');
            $('#batch_buttons').show();
            var count = dat.location.length - 1;
            for(i=0; i < count; i++){
                $('#batch_detail').append('<li>address: ' + dat.location[i].geoaddr_mdt + 'flag: ' + dat.location[i].flag_mdt+'</li>');
                $('#id_mdt').val(dat.location[i].id_mdt);
                $('#entrytype').val(dat.location[i].idedt_mdt);
                $('#name').val(dat.location[i].name_mdt);
                $('#geo_addr').val(dat.location[i].geoaddr_mdt);
                $('#telephone').val(dat.location[i].telephone_mdt);
                $('#email').val(dat.location[i].email_mdt);
                $('#geo_detail').val(dat.location[i].displayaddr_mdt);
                $('#website').val(dat.location[i].website_mdt);
                //$('#active').val(dat.location[i].active_mdt);
                var address = dat.location[i].geoaddr_mdt;
                // if address is not empty
                if(address != '') {
                    address_lookup(address, region, 'update');
                };
            };
        };

地址查询功能

function address_lookup(address, region, savetype) {
        // set default region
        if(region==null || region == '') {
            region = 'uk';
        };
        // address not empty
        if(address != '') {
            //clear existing markers<br />
            if(savetype == 'save'){
                removemarkers();
            };
            $('#geo_detail').html('<label>Geocoding address...</label>');
            // lookup the address
            geocoder.geocode( {'address':address,'region':region}, function(results, status) {
                // if the address was found
                if(status == google.maps.GeocoderStatus.OK) {
                    $str = '<label>Geocode Successful<br> Lattitude: '+results[0].geometry.location.lat()+' Longitude: '+results[0].geometry.location.lng()+'<br> The address is displayed below and will be stored in the database.<br> If the address is incorrect you may edit it before saving the location to the database.<br>If the marker is in the wrong location you may drag it to where you  believe it should be.</label>';
                    $('#geo_detail').html($str);
                    // insert lat/long into form
                    $('#lat').val(results[0].geometry.location.lat());
                    $('#lng').val(results[0].geometry.location.lng());
                    // create new lat/long object
                    latlng = new google.maps.LatLng(results[0].geometry.location.lat(),results[0].geometry.location.lng());
                    $('#disp_addr').val(address);
                    $('#form_buttons').show();
                    $('#detail_address').show();
                    //reverselookup(results[0].geometry.location.lat(), results[0].geometry.location.lng());
                    // set zoom option
                    map.setZoom(15);
                    // center the map on the new location
                    map.setCenter(results[0].geometry.location);
                    createMarker(map, latlng, true, false);
                    if(savetype ='update'){
                        savedata('update');
                    };
                    if(savedata='save'){
                        savedata('save');
                    };
                } else {
                    // display error
                    $('#geo_detail').append('<label>Geocoder failed to retrieve address: '+status+'</label>');
                    $('#disp_addr').val($('#geo_addr').val());
                };
            });
        };
    };

编辑回复Zacks第一评论----

我想在处理时显示每个结果,然后将结果输出到geo_detail div,以便返回已处理记录和相关错误消息的列表,理想情况下我希望选择让用户在处理时检查每条记录,这样循环就会暂停,直到用户找到保存按钮,这可能会将一个全局变量设置为true,我的循环会检查并等待,开始时我需要某种停顿这样各种ajax调用在处理下一条记录之前就有时间执行。

END EDIT ------------------------------ 任何想法或指示将不胜感激

感谢

1 个答案:

答案 0 :(得分:1)

我不认为“一切运行得太快”是对您遇到的任何问题的准确诊断。

我看到的一件事是你从其他ajax调用的成功fn启动了ajax调用。我不知道ajax lib是否可以重入。你可能想避免这种情况。

我这样做的方法是在混音中引入异步。使用setTimeout()调用processbatch()功能。然后,它将相对于第一个ajax调用异步运行。

同时考虑使用异步来调用goecoder。所有其他地理编码器请求完成后,仅发送新的地理编码器请求。你这样做,你马上发送它们。 (也许这就是你所说的“一切都跑得太快”)。

执行此操作的方法:接受一个地址对象和索引数组的address_lookup。在第i个地址上调用地理编码器。然后当调用完成(成功或失败)时,递增索引,并使用setTimeout再次调用address_lookup。

通过这种方式,您最多只能有一次对地理编码器的未完成调用。

在代码中看起来像这样:

var delay = 140;
function doAllAddresses(a, ix, callback) {

    // handle any addresses.
    // Test the list index for validity. If valid, 
    // Do the geocode, then increment the list index,
    // and call "myself" to handle additional 
    // addresses. When no more addresses remain, invoke
    // the 'done' callback.

    if (ix < a.length) {
        invokeGeocoderForOneAddress(a[ix], function() {
          // success function - gets invoked only when call to geocoder returns
          ix++;
          setTimeout(function(){doAllAddresses(ltr, ix, callback);}, delay);
        });
        return;
    }

    callback();
}

// kickoff:
doAllAddresses(addresses, 0, function() { alert("all addresses are done.");}); 

修改
ps:我建议你修改你的fn命名使用camelCase和verbNoun命名。所以,processBatch()lookupAddress(),而不是processbatch()address_lookup()


修改
以下是如何思考它:当您调用ajax调用时,您告诉浏览器发送HTTP请求。通常在您调用调用时,您会传递一个“成功”函数,当收到HTTP响应时,该函数会被调用。正如您所知,使用浏览器时,响应可以快速到达,也可以不那么快。当您在循环中调用ajax调用时,您告诉浏览器发送N个并发HTTP请求。不一定是你想要的。

我在这里建议的是一次调用一个AJAX调用(例如,到地址编码器)并且仅从成功fn调用下一个调用 - 也就是说,从第一个调用收到响应之后一。此外,如果您使用setTimeout()执行此操作,则将避免深度嵌套。