簡體   English   中英

是否可以在不創建全局回調函數的情況下異步初始化Google地圖?

[英]Is it possible to initialize Google Maps asynchronously without creating a global callback function?

我正在嘗試編寫一個可重復使用的插件模塊,以異步方式加載Google Maps並返回一個承諾。

這是我提出的代碼,使用AngularJS

但是,在“幕后”創建全局回調函數存在可重用性的缺點。 如果任何其他庫碰巧使用相同的命名空間,則可能導致錯誤的副作用。

我的問題 - 有沒有辦法在不創建全局變量的情況下實現這種效果。

下面是創建“邪惡”全局回調的代碼:

// 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功能。 請參閱此處的doc,這樣您就不必創建自己的機制來執行此操作。


但是,這就是說,如果你自己制作,你可以通過采取一些預防措施使你創建的全局名稱更隨機,使你的全局函數與其他人的代碼或甚至與你的庫的另一個實例發生碰撞的可能性大大降低。


這是一個如何使任何類型的命名沖突的幾率非常小的例子。 這使用三種技術:

  1. 在前綴上使用一些前導下划線。
  2. 在函數名稱中添加一個隨機數字序列。
  3. 在函數名稱中添加時間戳。
  4. 使用后刪除全局。

這是您實現這些方面的代碼。

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

演示獨特的函數名稱生成器: http//jsfiddle.net/jfriend00/oms7vc6o/

PS我自己並不認識Angular,但似乎Angular已經知道如何單獨進行JSONP調用,因此您不必在此處制作自己的解決方案。 有關詳細信息,請參閱此Angular文檔頁面以及此其他問題本文

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM