Еще один подход к возврату значения из асинхронной функции - передать объект, который сохранит результат от асинхронной функции.
Вот пример того же:
var async = require("async");
// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
// some asynchronous operation
$.ajax({
url: '...',
success: function(response) {
result.response = response;
_callback();
}
});
});
async.parallel(asyncTasks, function(){
// result is available after performing asynchronous operation
console.log(result)
console.log('Done');
});
Я использую объект result
для хранения значения во время асинхронной операции. Это позволяет получить результат даже после асинхронного задания.
Я использую этот подход много. Мне было бы интересно узнать, насколько хорошо этот подход работает, когда задействован результат обратно через последовательные модули.
Ничто не похоже на эти две строки в учебнике Майка Уильямса:
wait = true;
setTimeout("wait = true", 2000);
Вот порт версии 3:
http://acleach.me.uk /gmaps/v3/plotaddresses.htm
Соответствующим битом кода является
// ====== Geocoding ======
function getAddress(search, next) {
geo.geocode({address:search}, function (results,status)
{
// If that was successful
if (status == google.maps.GeocoderStatus.OK) {
// Lets assume that the first marker is the one we want
var p = results[0].geometry.location;
var lat=p.lat();
var lng=p.lng();
// Output the data
var msg = 'address="' + search + '" lat=' +lat+ ' lng=' +lng+ '(delay='+delay+'ms)<br>';
document.getElementById("messages").innerHTML += msg;
// Create a marker
createMarker(search,lat,lng);
}
// ====== Decode the error status ======
else {
// === if we were sending the requests to fast, try this one again and increase the delay
if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
nextAddress--;
delay++;
} else {
var reason="Code "+status;
var msg = 'address="' + search + '" error=' +reason+ '(delay='+delay+'ms)<br>';
document.getElementById("messages").innerHTML += msg;
}
}
next();
}
);
}
Вы используете неправильный путь setTimeout
. Сигналом функции (одной из) является setTimeout(callback, delay)
. Таким образом, вы можете легко указать, какой код следует запускать после какой задержки.
var codeAddress = (function() {
var index = 0;
var delay = 100;
function GeocodeCallback(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
new google.maps.Marker({ map: map, position: results[0].geometry.location, animation: google.maps.Animation.DROP });
console.log(results);
}
else alert("Geocode was not successful for the following reason: " + status);
};
return function(vPostCode) {
if (geocoder) setTimeout(geocoder.geocode.bind(geocoder, { 'address': "'" + vPostCode + "'"}, GeocodeCallback), index*delay);
index++;
};
})();
Таким образом, каждый вызов codeAddress()
приведет к тому, что geocoder.geocode()
будет вызван через 100 мс позже после предыдущего вызова.
Я также добавил анимацию в маркер, чтобы у вас был приятный эффект анимации с добавлением маркеров для сопоставления один за другим. Я не уверен, каков текущий лимит Google, поэтому вам может потребоваться увеличить значение переменной delay
.
Кроме того, если вы каждый раз геокодируете одни и те же адреса, вместо этого вы должны сохранить результаты геокодирования на свой db, а в следующий раз просто используйте их (чтобы вы сэкономили некоторый трафик, и ваше приложение будет немного бит быстрее)
Здесь я загрузил 2200 маркеров. Для добавления 2200 местоположений требуется около 1 минуты. https://jsfiddle.net/suchg/qm1pqunz/11/
//function to get random element from an array
(function($) {
$.rand = function(arg) {
if ($.isArray(arg)) {
return arg[$.rand(arg.length)];
} else if (typeof arg === "number") {
return Math.floor(Math.random() * arg);
} else {
return 4; // chosen by fair dice roll
}
};
})(jQuery);
//start code on document ready
$(document).ready(function () {
var map;
var elevator;
var myOptions = {
zoom: 0,
center: new google.maps.LatLng(35.392738, -100.019531),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map($('#map_canvas')[0], myOptions);
//get place from inputfile.js
var placesObject = place;
errorArray = [];
//will fire 20 ajax request at a time and other will keep in queue
var queuCounter = 0, setLimit = 20;
//keep count of added markers and update at top
totalAddedMarkers = 0;
//make an array of geocode keys to avoid the overlimit error
var geoCodKeys = [
'AIzaSyCF82XXUtT0vzMTcEPpTXvKQPr1keMNr_4',
'AIzaSyAYPw6oFHktAMhQqp34PptnkDEdmXwC3s0',
'AIzaSyAwd0OLvubYtKkEWwMe4Fe0DQpauX0pzlk',
'AIzaSyDF3F09RkYcibDuTFaINrWFBOG7ilCsVL0',
'AIzaSyC1dyD2kzPmZPmM4-oGYnIH_0x--0hVSY8'
];
//funciton to add marker
var addMarkers = function(address, queKey){
var key = jQuery.rand(geoCodKeys);
var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false';
var qyName = '';
if( queKey ) {
qyName = queKey;
} else {
qyName = 'MyQueue'+queuCounter;
}
$.ajaxq (qyName, {
url: url,
dataType: 'json'
}).done(function( data ) {
var address = getParameterByName('address', this.url);
var index = errorArray.indexOf(address);
try{
var p = data.results[0].geometry.location;
var latlng = new google.maps.LatLng(p.lat, p.lng);
new google.maps.Marker({
position: latlng,
map: map
});
totalAddedMarkers ++;
//update adde marker count
$("#totalAddedMarker").text(totalAddedMarkers);
if (index > -1) {
errorArray.splice(index, 1);
}
}catch(e){
if(data.status = 'ZERO_RESULTS')
return false;
//on error call add marker function for same address
//and keep in Error ajax queue
addMarkers( address, 'Errror' );
if (index == -1) {
errorArray.push( address );
}
}
});
//mentain ajax queue set
queuCounter++;
if( queuCounter == setLimit ){
queuCounter = 0;
}
}
//function get url parameter from url string
getParameterByName = function ( name,href )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( href );
if( results == null )
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
//call add marker function for each address mention in inputfile.js
for (var x = 0; x < placesObject.length; x++) {
var address = placesObject[x]['City'] + ', ' + placesObject[x]['State'];
addMarkers(address);
}
});
Использование «setInterval» & amp; «clearInterval» устраняет проблему:
function drawMarkers(map, markers) {
var _this = this,
geocoder = new google.maps.Geocoder(),
geocode_filetrs;
_this.key = 0;
_this.interval = setInterval(function() {
_this.markerData = markers[_this.key];
geocoder.geocode({ address: _this.markerData.address }, yourCallback(_this.markerData));
_this.key++;
if ( ! markers[_this.key]) {
clearInterval(_this.interval);
}
}, 300);
}