Javascript 是否可以在不创建全局回调函数的情况下异步初始化Google Maps?
我正在尝试编写一个可重用的插件模块,以异步加载Javascript 是否可以在不创建全局回调函数的情况下异步初始化Google Maps?,javascript,angularjs,google-maps,google-maps-api-3,asynchronous,Javascript,Angularjs,Google Maps,Google Maps Api 3,Asynchronous,我正在尝试编写一个可重用的插件模块,以异步加载googlemaps,并返回一个承诺 然而,在“幕后”创建全局回调函数存在可重用性缺陷。这是一个可能导致bug的副作用,如果相同的名称空间碰巧被任何其他库使用 我的问题是,有没有办法在不创建全局变量的情况下实现这种效果 下面是创建“邪恶”全局回调的代码: // Google async initializer needs global function, so we use $window angular.module('GoogleMapsIni
googlemaps
,并返回一个承诺
然而,在“幕后”创建全局回调函数存在可重用性缺陷。这是一个可能导致bug的副作用,如果相同的名称空间碰巧被任何其他库使用
我的问题是,有没有办法在不创建全局变量的情况下实现这种效果
下面是创建“邪恶”全局回调的代码:
// Google async initializer needs global function, so we use $window
angular.module('GoogleMapsInitializer')
.factory('Initializer', function($window, $q){
// maps loader deferred object
var mapsDefer = $q.defer();
// Google's url for async maps initialization accepting callback function
var asyncUrl = 'https://maps.googleapis.com/maps/api/js?callback=';
// async loader
var asyncLoad = function(asyncUrl, callbackName) {
var script = document.createElement('script');
//script.type = 'text/javascript';
script.src = asyncUrl + callbackName;
document.body.appendChild(script);
};
// Here is the bad guy:
// callback function - resolving promise after maps successfully loaded
$window.googleMapsInitialized = function () {
mapsDefer.resolve();
};
// loading google maps
asyncLoad(asyncUrl, 'googleMapsInitialized');
return {
// usage: Initializer.mapsInitialized.then(callback)
mapsInitialized : mapsDefer.promise
};
})
从您所指的跨源域上的服务器获取数据的脚本加载技术是JSONP。你可以阅读更多关于它的内容。根据定义,JSONP只能通过调用全局作用域函数来工作 因此,直接回答您的问题:不,没有全局函数,您不能使用JSONP跨源技术——这就是机制的工作原理。脚本在全局命名空间中执行,它必须调用它可以从全局命名空间访问的函数。甚至jQuery和YUI也做了类似的事情来实现JSONP 而且,由于您使用的是Angular,它已经内置了JSONP功能。看,这样你就不必创建自己的机制来实现这一点
但是,也就是说,如果您正在创建自己的全局函数,您可以通过采取一些预防措施,使您创建的全局名称更加随机,从而大大降低全局函数与其他任何代码甚至与库的另一个实例发生冲突的可能性
下面是一个示例,说明如何使任何类型的命名冲突发生的几率非常小。这使用了三种技术:
// Google async initializer needs global function, so we use $window
angular.module('GoogleMapsInitializer')
.factory('Initializer', function($window, $q){
// maps loader deferred object
var mapsDefer = $q.defer();
// Google's url for async maps initialization accepting callback function
var asyncUrl = 'https://maps.googleapis.com/maps/api/js?callback=';
// async loader
var asyncLoad = function(asyncUrl, callbackName) {
var script = document.createElement('script');
//script.type = 'text/javascript';
script.src = asyncUrl + callbackName;
document.body.appendChild(script);
};
// generate a unique function name
// includes prefix, current time and random number
var fname = "__googleMapsInitialized_" +
(new Date().getTime()) + "_" +
(Math.random() + "").replace(".", "");
// callback function - resolving promise after maps successfully loaded
$window[fname] = function () {
mapsDefer.resolve();
// remove the global now that we're done with it
delete $window[fname];
};
// loading google maps
asyncLoad(asyncUrl, fname);
return {
// usage: Initializer.mapsInitialized.then(callback)
mapsInitialized : mapsDefer.promise
};
})
唯一函数名生成器的演示:
另外,我自己也不知道Angular,但Angular似乎已经知道如何单独进行JSONP调用,所以您不必在这里制定自己的解决方案。有关详细信息,请参阅和。添加了对另一篇文章的参考,该文章向您展示了如何在这个JSONP调用中使用内置的角度功能,而不是创建自己的JSONP机制。+1回答得很好!完全忘记了
JSONP
,希望谷歌的同事在给出代码示例时提到它。结果表明,谷歌地图不支持JSONP
(),该调用实际上不是JSONP
,因此不能与Angular的$http.JSONP
一起使用,请参阅。所以,唯一的办法就是使用你的绝妙解决方案,这很有效@DmitriZaitsev-大多数人只是使用Google的JS接口来访问Google Maps:让他们担心请求的细节。@DmitriZaitsev-Google Maps似乎使用了整个JSONP机制,但生成的结果是一个已经形成的javascript对象,而不是一段可以解析为对象的JSON文本。因此,它不适用于标准JSONP处理代码。我仍然建议你只使用谷歌JSAPI来制作地图,而不必担心这些细节。