为什么我的Google Maps API回调在前面的内联脚本之前执行


<script src="/js/site.js?v=EtZhOXlkRte5HDRXpfS7rDy3ua0sbCvtNJUaIlNsSXw"></script>
<script>
var init;
$(function () {
var adpSummaryListenerId;
init = _initializeDirections;
initializeAdpSummaryListener();
function _initializeDirections() {
console.log("test"); //we don't get here, sometimes
var origin = {
isGoogle: $("#origin-isgoogle").val(),
coordinate: new google.maps.LatLng(@origin.Latitude, @origin.Longitude),
address: "@origin.StreetAddress",
marker: "@origin.MarkerName"
}, destination = {
isGoogle: $("#destination-isgoogle").val(),
coordinate: new google.maps.LatLng(@destination.Latitude, @destination.Longitude),
address: "@destination.StreetAddress",
marker: "@destination.MarkerName"
}, start = {
value: origin.isGoogle ? origin.address : origin.coordinate,
pos: origin.coordinate,
marker: origin.marker
}, end = {
value: destination.isGoogle ? destination.address : destination.coordinate,
pos: destination.coordinate,
marker: destination.marker
};
console.log("Initializing directions");
initializeDirections(start, end); //in site.js
}
function initializeAdpSummaryListener() {
adpSummaryListenerId = window.setInterval(addNavigateButton, 500);
}
function addNavigateButton() {
console.log("checking for .adp-summary");
if ($(".adp-summary").length) {
$(".adp-summary").append($("#start-navigation").html());
clearInterval(adpSummaryListenerId);
}
}
});
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=@(Model.GoogleMapsApiKey)&callback=init"></script>

我不明白为什么,尽管地图脚本在内联脚本之后被引用,但谷歌地图API回调init有时在谷歌尝试调用它之前没有实例化

这是我得到的错误:

Uncaught (in promise)
ld {message: "init is not a function", name: "InvalidValueError", stack: "Error at new ld (https://maps.googleapis.com/.......&callback=init:141:124"}

我以前在site.js中声明了回调名称initializeMap作为引用(但仍然在内联脚本中初始化(,但为了简洁和孤立,我将其移到了这里,希望我能够解决这个问题。但同样的问题依然存在。

我知道async指示在解析的同时提取api,并在它可用时立即进行评估,但它不应该在内联脚本之前可用,对吧?

我也理解defer表示在解析文档之后才会执行api,所以它仍然不可用。

我确实看到了defer:

此属性允许消除阻止JavaScript的解析器,因为浏览器在继续解析之前必须加载和评估脚本。在这种情况下,async也有类似的效果。

但是defer仍然不应该阻止内联脚本首先执行,因为如果在内联<script>标记上使用属性,它只允许JavaScript不必是解析器阻塞

所以我不知所措。

您上面的内联脚本确实是首先运行的,但$(function () {是一个jQuery构造,它只在文档准备好后才在内部运行回调。看起来谷歌脚本是第一个运行的。

如果您为Google的脚本提供defer属性,它将只在DOM构建完成后运行,而$(function () {将是不必要的。因此,只需将所有内容从$(function () {中移出,使init处于顶级,并在加载谷歌脚本时由谷歌调用:

<script>
function init() {
var origin = {
isGoogle: $("#origin-isgoogle").val(),
coordinate: new google.maps.LatLng(@origin.Latitude, @origin.Longitude),
address: "@origin.StreetAddress",
marker: "@origin.MarkerName"
}, destination = 
// etc

请注意,虽然您可以使用asyncdefer,但不应该同时使用这两种。要等待DOM加载,请使用defer而不是async

除了分配给变量之外,上面的内联脚本还有一件事情要做,那就是调用initializeAdpSummaryListener。如果需要确保DOM在运行前已加载,可以将其放入$(function () {中:

$(initializeAdpSummaryListener);

另一个控制流可能更容易理解的选项是将所有都放在谷歌加载时调用的命名函数中(给定defer属性,只有在页面加载时才会发生(。

最新更新