JavaScript似乎不等待返回值

Geo*_*ker 26 javascript asynchronous callback asynccallback

我一直在努力解决这个问题.我是Javascript的新手,并且一直认为我写的代码已经异步运行了.这是一个通用的例子:

我在函数a中运行了一些代码.函数A然后调用函数B,函数B需要将变量返回给A,因此A可以在以后的操作中使用它.看来,当A调用B时,它仍然继续运行自己的代码,而不是等待其返回值被阻塞,并且B不够快,使得A最终到达需要使用返回的点值,我得到一个未定义的变量类型错误.

我解决这个问题的方法是函数A调用函数B然后调用一个函数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);
}
Run Code Online (Sandbox Code Playgroud)

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

所以问题是makeMap需要Geocode函数获得的纬度和经度值,但是在控制台中我得到一个错误,说结果是未定义的.到底是怎么回事?我来自Java,所以我对JS中数据流的发生方式感到有些困惑!这将是未来的宝贵经验!

关于一个问题:我应该如何在外部脚本之间拆分我的功能?什么是好习惯?我的所有功能都应该塞进一个外部.js文件中,还是应该将功能组合在一起?

jnc*_*ton 35

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

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);
        }
   });

}

...
Run Code Online (Sandbox Code Playgroud)


T.J*_*der 12

我...的印象是我写的代码一直在异步运行.

是的,它确实.您的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);
        }
   });
}
Run Code Online (Sandbox Code Playgroud)

相反,您必须对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
        }
   });
}
Run Code Online (Sandbox Code Playgroud)

然后,而不是像这样使用它:

var results = geocode(someArgHere);
if (results) {
    doSomething(results);
}
else {
    doSomethingElse();
}
Run Code Online (Sandbox Code Playgroud)

你这样称呼它:

geocode(someArgHere, function() {
    if (results) {
        doSomething(results);
    }
    else {
        doSomethingElse();
    }
});
Run Code Online (Sandbox Code Playgroud)

例如,你完全异步.