2011-11-06 130 views
11

我需要從另一個js文件中的外部js文件使用JavaScript函數。這基本上是我試過的代碼:我可以在沒有回調的情況下使用jquery getScript()嗎?

$.getScript('js/myHelperFile.js'); 
myHelperFunction(); 

這不工作 - 我得到「沒有定義myHelperFunction」的錯誤。

然而,此代碼的工作:

$.getScript('js/myHelperFile.js', function(){myHelperFunction();}); 

我特別希望能夠做到這一點的第一種方式 - 加載在我的文件的開頭的文件,然後使用我從那裏需要的任何功能。這是可能的,還是我誤解getScript的工作原理?

回答

29

這樣做「第一種方式」目前不是*可能與jQuery.getScript,因爲它只支持異步操作,因此它被調用後立即返回。

由於在腳本嘗試調用myHelperFunction(),myHelperFunction時出現腳本下載之前,它會返回undefined並導致該錯誤。

*看到這個答案的底部有前途的新方法,最終將讓你編寫代碼,幾乎就像你所需的樣式更新。

你可以使用jQuery.ajaxasync設置設爲false與代碼是這樣做的:

$.ajax({ 
    url: 'js/myHelperFile.js', 
    async: false, 
    dataType: "script", 
}); 

myHelperFunction(); 

documentation狀態:

同步請求可能暫時鎖定瀏覽器,在請求處於活動狀態時禁用任何操作。

這是一件非常糟糕的事情。如果提供myHelperFile.js的服務器在任何時間響應都很慢(某些時候將發生),則該頁面將變爲無響應狀態,直到請求結束或超時。

接受在整個jQuery中大量使用的回調風格將是一個更好的主意。

$.getScript('js/myHelperFile.js', function() { 
    myHelperFunction(); 
}); 

你並不需要或者可以使用匿名函數,你可以把你的代碼在名爲功能:

function doStuffWithHelper() { 
    myHelperFunction(); 
} 

$.getScript('js/myHelperFile.js', doStuffWithHelper); 

如果您需要在調用之前加載多個依賴myHelperFunction除非您在執行代碼之前設置了某種系統來確定是否下載了所有依賴項,否則這將不起作用。然後,您可以在所有.getScript調用中設置回調處理程序,以檢查是否在運行代碼之前加載了所有依賴項。

var loadedScripts = { 
    myHelperFile: false, 
    anotherHelperFile: false 
}; 

function doStuffWithHelper() { 
    // check to see if all our scripts are loaded 
    var prop; 
    for (prop in loadedScripts) { 
     if (loadedScripts.hasOwnProperty(prop)) { 
      if (loadedScripts[prop] === false) { 
       return; // not everything is loaded wait more 
      } 
     } 
    } 

    myHelperFunction(); 
} 

$.getScript('js/myHelperFile.js', function() { 
    loadedScripts.myHelperFile = true; 
    doStuffWithHelper(); 
}); 
$.getScript('js/anotherHelperFile.js', function() { 
    loadedScripts.anotherHelperFile = true; 
    doStuffWithHelper(); 
}); 

正如您所看到的,這種方法變得複雜且難以維護。

如果您確實需要加載多個依賴關係,您最好使用諸如yepnope.js這樣的腳本加載器來執行此操作。

yepnope({ 
     load : [ 'js/myHelperFile.js', 'js/anotherHelperFile.js' ], 
     complete: function() { 
      var foo; 
      foo = myHelperFunction(); 
      foo = anotherHelperFunction(foo); 
      // do something with foo 
     } 
}); 

Yepnope使用回調只是想.getScript,所以你不能用你想堅持使用順序的風格。這是一個很好的折衷,但因爲在同一行中執行多個同步調用只會複合該方法的問題。


更新2013年12月8日

jQuery 1.5 release,提供了這樣做的另一個純jQuery的方式。作爲1.5,所有的AJAX請求返回Deferred Object,所以你可以這樣做:

$.getScript('js/myHelperFile.js').done(function() { 
    myHelperFunction(); 
}); 

作爲一個異步請求,這當然需要一個回調。然而,使用Deferreds擁有傳統的回調製度的巨大優勢,使用$.when()你可以很容易地擴展爲加載多個先決條件腳本,而無需自己錯綜複雜的跟蹤系統:

$.when($.getScript('js/myHelperFile.js'), $.getScript('js/anotherHelperFile.js')).done(function() { 
    var foo; 
    foo = myHelperFunction(); 
    foo = anotherHelperFunction(foo); 
    // do something with foo 
}); 

這將同時下載腳本和只執行回調之後他們都被下載了,就像上面的Yepnope示例一樣。


更新2014年3月30日

最近,我讀an article讓我意識到一個新的JavaScript功能,可能在未來實現那種程序,尋找至今沒有異步代碼的那你想用! Async Functions將使用await關鍵字來暫停執行async函數,直到異步操作完成。壞消息是,它目前將被納入ES7,兩個ECMAScript版本。

await依賴於您正在等待的異步函數返回Promise。我不確定瀏覽器實現的行爲方式,如果它們需要一個真正的ES6 Promise對象,或者其他實現的承諾(如jQuery從AJAX調用返回)就足夠了。如果需要ES6承諾,你將需要包裝jQuery.getScript與返回無極功能:

"use strict"; 
var getScript = function (url) { 
    return new Promise(function(resolve, reject) { 
    jQuery.getScript(url).done(function (script) { 
     resolve(script); 
    }); 
    }); 
}; 

然後你可以用它來下載和await,然後再繼續:

(async function() { 
    await getScript('js/myHelperFile.js'); 
    myHelperFunction(); 
}()); 

如果你是真的決定今天寫這種風格,你可以使用asycawait,然後用Traceur將代碼轉換成可以在當前瀏覽器中運行的代碼。這樣做的附加好處是你也可以使用很多other useful new ES6 features

+0

令人驚訝的全面的答案,做得好! – GregL

+0

+!相當完整的答案。 Howerever,如果你爲jQuery加載時爲什麼要迭代for..in'合成器? –

+0

@ gion_13它允許我從內部返回if(loadedScripts [prop] === false){'退出該函數,以便下列依賴於依賴關係的代碼不會運行。如果我使用'$ .each',我可以用'return false'儘早停止循環,但是循環後面的代碼會運行,我必須在循環之前設置某種標誌,然後在循環之後檢查它以防止代碼運行。使用'for..in'循環並退出函數更清晰。現在看看它,而不是字典,我會只使用一個計數變量,並將其與全部腳本進行比較。 –

2

單獨使用getScript()函數,我認爲你不能。問題在於使用AJAX加載腳本(實際上,getScript只是一個特殊的$.ajax()函數的簡寫),並且當瀏覽器嘗試在下一行執行該函數時,服務器可能尚未返回該文件。

如果你不希望使用一個回調函數,你需要使用jQuery的$.ajax()功能的原始形式(而忽略了getScript()),並設置轉移爲同步。通過這種方式,你可以肯定的是,該腳本將你的代碼的執行之前加載繼續:

$.ajax({ 
    url: url, 
    dataType: "script", 
    async: false 
}); 
2

$ .getScript,真的所有HTTP OP相關的jQuery的功能是默認情況下非阻塞調用。也就是說,在操作完成時代碼不會掛起。這意味着上面的代碼肯定會失敗,因爲在試圖執行方法的行運行之前,$ .getScript將無法加載腳本。這就是回調函數被接受爲參數的原因。

但是,你想要做的是可能的。腳本加載後,您應該可以從任何地方調用它。在下載腳本之前避免調用方法的所有必要條件是設置必要的標誌。

var HelperFileLoaded = false; 
$.getScript('js/myHelperFile.js', function() { HelperFileLoaded = true; }); 

// ... 

function btnSaveClick() { 
    if(!HelperFileLoaded) return; 
    myHelperFunction(); 
} 

BenM的建議是可行的,但除非你只想進行一次調用myHelperFunction也不會作爲解決方案的工作,因爲會有不保證該腳本將之前的任何其他方法調用myHelperFunction有下載被觸發。

0

如果您使用JSONP,您的第一個工作正常,我經常這樣做。

相關問題