JQuery приостановки цикла, пока не будет выполнено глобальное условие - PullRequest
0 голосов
/ 08 ноября 2010

хорошо, у меня есть вызов 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());
                };
            });
        };
    };

РЕДАКТИРОВАТЬ в ответ на первый комментарий Закса ----

я хочу показать каждый результат в процессе его обработки,затем выведите результат в div geo_detail, чтобы получить список обработанных записей и связанных сообщений об ошибках, которые возвращаются, в идеале я бы хотел, чтобы пользователь каждый раз просматривалшнур, как он обрабатывается, поэтому цикл приостанавливается до тех пор, пока пользователь не нажмет кнопку сохранения, которая, возможно, установит глобальную переменную в true, которую мой цикл будет проверять и ждать, но для начала мне понадобится какая-то пауза, чтобыразличные ajax-вызовы успевают выполнить перед обработкой следующей записи.

END EDIT ----------------------------- любые идеи или указатели будут высоко оценены

спасибо

1 Ответ

1 голос
/ 08 ноября 2010

Я не думаю, что «все идет слишком быстро» - это точный диагноз любой проблемы, с которой вы столкнулись.

Одна вещь, которую я вижу, состоит в том, что у вас есть вызовы ajax, инициированные после успеха других вызовов ajax. Я не знаю, является ли библиотека Ajax повторной. Вы можете избежать этого.

Я бы сделал так, чтобы ввести асинхронность в микс. Используйте setTimeout() для вызова функции processbatch(). Затем он будет работать асинхронно относительно первого вызова Ajax.

Также рассмотрите возможность использования асинхронности для вызова goecoder. Отправляйте новый запрос геокодера только после выполнения всех других запросов геокодера. То, как вы это делаете, вы отправляете их всех сразу. (Может быть, это то, что вы подразумеваете под «все работает слишком быстро»).

Способ сделать это: принять в ваш address_lookup fn массив адресных объектов и индекс. Вызов геокодера по 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.");}); 

EDIT
PS: Я рекомендую вам исправить ваши имена FN для использования имен CamelCase и verbNoun. Итак, processBatch() и lookupAddress(), а не processbatch() и address_lookup().


EDIT
Вот как следует об этом подумать: когда вы вызываете ajax-вызов, вы говорите браузеру отправить HTTP-запрос. Обычно во время вызова вы передаете функцию «success», которая вызывается для вас при получении ответа HTTP. Как вы знаете из браузера, ответ может прийти быстро или не так быстро. Когда вы вызываете ajax-вызовы в цикле, вы говорите браузеру отправлять N одновременных HTTP-запросов. Не обязательно то, что вы хотите.

То, что я предлагаю здесь, - это вызывать по одному вызову AJAX за раз (например, геокодеру) и вызывать только следующий вызов с успехом fn, то есть ПОСЛЕ того, как ответ получен от первого один. Также, если вы сделаете это с помощью setTimeout(), вы избежите глубокого вложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...