JavaScript 似乎不等待返回值



我已经为此挣扎了一段时间。我是Javascript的新手,一直觉得我编写的代码是异步运行的。下面是一个通用示例:

我在函数a中运行了一些代码。然后,函数a调用函数B,后者需要向a返回一个变量,以便a在以后的操作中使用它。然而,当A调用B时,它似乎仍然继续运行自己的代码,而不是等待阻止返回值,而B的速度不够快,以至于A最终达到了需要使用返回值的地步,我得到了一个未定义变量类型错误

我处理这个问题的方法是让函数A调用函数B,然后函数B调用函数C,函数C将执行A对返回值的后续操作。。。。我正在通过调用而不是返回来序列化我的代码。。。虽然这很麻烦。。。

以下是实际代码中发生这种情况的示例:

function initialize() {
//Geocode Address to obtin Lat and Long coordinates for the starting point of our map
geocoder = new google.maps.Geocoder();
var results = geocode(geocoder);
makeMap(results[0].geometry.location.lat(), results[0].geometry.location.lng());
}
function geocode(geocoder) {
//do geocoding here...
var address = "3630 University Street, Montreal, QC, Canada";
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
return results;
}
else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
function makeMap(lat, long) {
//  alert(lat); for debuging
var mapOptions = {
center: new google.maps.LatLng(lat, long),
zoom: 17,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),
mapOptions);
}

注意:initialize由我的html中的body onload="initialize()"调用。

所以问题是makeMap需要Geocode函数获得的纬度和经度值,但我在控制台中收到一个错误,说结果是未定义的。发生了什么事?我来自Java,所以我对JS中的数据流是如何发生的有点困惑!这将是对未来的宝贵教训!

还有一个问题:我应该如何在外部脚本中划分函数?什么是良好的做法?我应该把所有的函数都塞进一个外部.js文件中,还是应该把类似的函数组合在一起?

您似乎对这个问题有很好的理解,但听起来似乎不熟悉解决它的方法。解决这个问题最常见的方法是使用回调。这基本上是等待返回值的异步方式。以下是如何在您的情况下使用它:

function initialize() {
//Geocode Address to obtin Lat and Long coordinates for the starting point of our map
geocoder = new google.maps.Geocoder();
geocode(geocoder, function(results) {
// This function gets called by the geocode function on success
makeMap(results[0].geometry.location.lat(), results[0].geometry.location.lng());        
});
}
function geocode(geocoder, callback) {
//do geocoding here...
var address = "3630 University Street, Montreal, QC, Canada";
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// Call the callback function instead of returning
callback(results);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
...

我。。。我一直觉得我一直在写的代码是异步运行的。

是的。geocode函数无法将调用结果返回到Google API,因为该函数在Google调用完成之前返回。参见以下注释:

function geocode(geocoder) {
//do geocoding here...
var address = "3630 University Street, Montreal, QC, Canada";
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// +---------- This doesn't return anything from your
// v           geocode function, it returns a value from the callback
return results;
}
else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}

相反,您必须对geocode函数进行编码,以便它接受回调,并在得到结果时调用该回调。例如:

// Added a callback arg ---v
function geocode(geocoder, callback) {
//do geocoding here...
var address = "3630 University Street, Montreal, QC, Canada";
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// v---------- Call the callback
callback(results);
}
else {
alert("Geocode was not successful for the following reason: " + status);
callback(null); // <--- Call the callback with a flag value
// saying there was an error
}
});
}

然后,不要像这样使用它:

var results = geocode(someArgHere);
if (results) {
doSomething(results);
}
else {
doSomethingElse();
}

你这样称呼它:

geocode(someArgHere, function() {
if (results) {
doSomething(results);
}
else {
doSomethingElse();
}
});

例如,您完全异步地执行

匿名函数内部的return语句从匿名函数返回,而不是从外部地理编码函数返回。地理编码函数返回undefined。geocoder.geocode方法可以随时调用匿名函数,同步或异步。查看文档。

事实上,您正确地认识到调用是异步的,并且没有获得正确的返回值。

通常,在js中调用函数时,它们是同步的。

e.g. a() calls b(), and a() waits until b() to finish before continuing.

但是,在某些情况下,例如进行ajax或jsonp调用,它是异步完成的。这正是当您调用geocode()时发生的情况。

你的执行:

initialize() is called;
initialize() calls geocoder();
geocoder makes a request to Google, and returns null in the meantime.
initialze() calls makemap()
the Google geocoder returns at some point, and executed the success callback, which you have defined as "return results;", but there is nothing to return, since the function has already ended.

因此,特别是,利用已经内置在地理编码器调用中的回调:

if (status == google.maps.GeocoderStatus.OK) {
makeMap(results);
}

最新更新