jqueryが読み込まれるまでスクリプトの実行を待機させる方法


106

ページの読み込みが非常に速く、jqueryが後続のスクリプトによって呼び出される前に読み込みが完了しないという問題が発生しています。jqueryの存在を確認する方法はありますか。jqueryが存在しない場合は、しばらく待ってから再試行してください。


以下の回答/コメントに応じて、マークアップの一部を投稿しています。

状況... asp.netマスターページと子ページ。

マスターページには、jqueryへの参照があります。次に、コンテンツページに、ページ固有のスクリプトへの参照があります。ページ固有のスクリプトが読み込まれると、「$が定義されていません」というメッセージが表示されます。

マークアップのいくつかのポイントにアラートを配置して、発生する順序を確認し、この順序で発生することを確認しました。

  1. マスターページのヘッダー。
  2. 子ページコンテンツブロック1(マスターページのヘッド内にありますが、マスターページスクリプトが呼び出された後)。
  3. 子ページコンテンツブロック2。

マスターページの上部にあるマークアップは次のとおりです。

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="SiteMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Reporting Portal</title>
    <link href="~/Styles/site.css" rel="stylesheet" type="text/css" />
    <link href="~/Styles/red/red.css" rel="stylesheet" type="text/css" />
    <script type="text/Scripts" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> 
    <script type="text/Scripts" language="javascript" src="../Scripts/jquery.dropdownPlain.js"></script>
    <script type="text/Scripts" language="javascript" src="../Scripts/facebox.js"></script>
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>

次に、マスターページの本文に、追加のContentPlaceHolderがあります。

 <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
                </asp:ContentPlaceHolder>

子ページでは、次のようになります。

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Dashboard.aspx.cs" Inherits="Data.Dashboard" %>
<%@ Register src="../userControls/ucDropdownMenu.ascx" tagname="ucDropdownMenu" tagprefix="uc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
    <link rel="stylesheet" type="text/css" href="../Styles/paserMap.css" />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
***CONTENT HERE***
    <script src="../Scripts/Dashboard.js" type="text/javascript"></script>
</asp:Content>

「../Script/Dashboard.js」ファイルの内容は次のとおりです。

    $(document).ready(function () {

    $('.tgl:first').show(); // Show the first div

    //Description: East panel parent tab navigation
    $('.tabNav label').click(function () {
        $('.tabNav li').removeClass('active')
        $(this).parent().addClass('active');

        var index = $(this).parent('li').index();
        var divToggle = $('.ui-layout-content').children('div.tgl');

        //hide all subToggle divs
        divToggle.hide();
        divToggle.eq(index).show();
    });

});

4
使ってるの$(document).ready(function(){...});
ロウネージ2011

単純な<script src="...">タグを含むスクリプトを読み込んでいる場合、それは起こり得ません。RequireJSやLABjsなどを使用していますか?
ポインティ2011

$(document).ready()またはで後続のスクリプトを実行していますか$(window).load()?例を見てもらえますか?
John Hartsock、2011

1
@AmandaMyer、今はすでにドキュメントを使用しているため、すべての提案を無視します。すでにそうしているためですが、Mimetypeが原因で、同期読み込みが行われていません
Sander

2
に変更type="text/Scripts"してみてくださいtype="text/javascript"。または、すべて不要になるようにまとめて削除してくださいlanguage="javascript。また、も削除してください。物事を試してみるかもしれません。
ジャック

回答:


11

編集する

スクリプトタグの正しいタイプを試していただけませんか?text/ScriptsJavaScriptの正しいMIMEタイプではないを使用しているようです。

これを使って:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> 
<script type="text/javascript" src="../Scripts/jquery.dropdownPlain.js"></script>
<script type="text/javascript" src="../Scripts/facebox.js"></script>

編集を終了

または、JavaScriptコードのローダーであるrequire.jsを確認することもできます。

プロジェクトによっては、これは少しやり過ぎかもしれません


204

パーティーの後半、Briguy37の質問に似ていますが、将来の参照のために、次のメソッドを使用して、jQueryがロードされるまで延期する関数を渡します。

function defer(method) {
    if (window.jQuery) {
        method();
    } else {
        setTimeout(function() { defer(method) }, 50);
    }
}

window.jQuery存在し、終了して呼び出すまで、50ミリ秒ごとにdeferメソッドを再帰的に呼び出します。method()

無名関数の例:

defer(function () {
    alert("jQuery is now loaded");
});

2
これは私にはうまくいきませんでした。メソッドの内部では、$は定義されていません...理由はまだわかりません。
アーロンリフシン

これは、Adobe Museの他の誰かが設計したサイトでカスタムコードを機能させるための優れたソリューションでした。
バガビル

@gidimタイマーではなくループなので、そうなりません。ただし、ユーザーがページにとどまっている限り、実行を続けます。
マイクロ2017年

スクリプトの読み込み順序を調査することをお勧めします。scriptjQueryをロードするタグにdefer属性がある場合、コードで定義されたスクリプトの順序に関係なく、後でロードしないことで問題が発生することがわかりました。
ADTC

19

defer属性を使用して、実際にスクリプトをロードできます。

<script type='text/javascript' src='myscript.js' defer='defer'></script>

ただし、通常はスクリプトを正しい順序でロードすることで問題が解決するので、jqueryをスクリプトの前に配置してください。

コードがページ内にあり、個別のjsファイル内にない場合、ドキュメントの準備ができて、次のようにコードをカプセル化すると、スクリプトを実行する必要があります。

$(function(){
//here goes your code
});

これは、単一の依存関係がある限り問題ありません
GuillaumeMassé12年

16

これを行うためのさらに別の方法ですが、Darbioの遅延メソッドはより柔軟です。

(function() {
  var nTimer = setInterval(function() {
    if (window.jQuery) {
      // Do something with jQuery
      clearInterval(nTimer);
    }
  }, 100);
})();

16

最も簡単で安全な方法は、次のようなものを使用することです。

var waitForJQuery = setInterval(function () {
    if (typeof $ != 'undefined') {

        // place your code here.

        clearInterval(waitForJQuery);
    }
}, 10);

2
天才ソリューション。ありがとう
Diego Fortes

13

onloadイベントを試すことができます。すべてのスクリプトが読み込まれたときに発生します:

window.onload = function () {
   //jquery ready for use here
}

ただし、window.onloadが使用している他のスクリプトをオーバーライドできることに注意してください。


これは機能しますが、jqueryがページの外観を変更すると、おそらくスタイルのないコンテンツのフラッシュが表示されます
Matthew Lock

1
イベントリスナーを追加して、他のスクリプトを上書きしないようにすることができます:stackoverflow.com/a/15564394/32453 FWIW '
rogerdpack

@rogerdpackは同意する、それはより良い解決策です。
Nigrimmist

10

提案された解決策は非同期コードを気にしながらのみ機能することがわかりました。どちらの場合でも機能するバージョンは次のとおりです。

document.addEventListener('DOMContentLoaded', function load() {
    if (!window.jQuery) return setTimeout(load, 50);
    //your synchronous or asynchronous jQuery-related code
}, false);

おかげで、ロード時に1回、フォールバックの開始が50msごとにループするのを確認することは、トップ投票の回答のようにsetIntervalでループさせるよりもはるかに優れています。最良のケースでは、トップ回答の平均的なケースである25msではなく、0msの遅延があります。
リュック

素晴らしくエレガント- load関数を渡す方法が好きですが、それをで再利用することもできますsetTimeout
ネメサリアル

6

これはよくある問題です。クールなPHPテンプレートエンジンを使用して、基本的なレイアウトがあると想像してください。

HEADER
BODY ==> dynamic CONTENT/PAGE
FOOTER

そしてもちろん、ページの下部でJavaScriptをロードする方が良い場所を読んで、動的コンテンツがjQuery(または$)が誰であるかを知らないようにします。

また、小さなJavascriptをインライン化するのが良い場所を読んでいるので、ページにjQueryが必要だと想像してください。

Facebookが提供するソリューションが大好き

window.fbAsyncInit = function() { alert('FB is ready !'); }

したがって、怠惰なプログラマー(私は良いプログラマー^^と言うべきです)として、(ページ内で)同等のものを使用できます。

window.jqReady = function() {}

そして、jQuery includeの後に、レイアウトの下部に追加します

if (window.hasOwnProperty('jqReady')) $(function() {window.jqReady();});

ありがとう!それがまさに私が直面しているケースです。
KumZ

または、jqueryの負荷を一番上に移動します:) stackoverflow.com/a/11012073/32453
rogerdpack

5

「待機」(通常はを使用して行われsetTimeoutます)ではなく、ウィンドウ自体でのjQueryオブジェクトの定義をフックとして使用して、それに依存するコードを実行することもできます。これは、を使用して定義されたプロパティ定義を通じて実現できますObject.defineProperty

(function(){
  var _jQuery;
  Object.defineProperty(window, 'jQuery', {
    get: function() { return _jQuery; },
    set: function($) {
      _jQuery = $;

      // put code or call to function that uses jQuery here

    }
  });
})();

jQueryが実際にウィンドウプロパティを定義した場合、これは漠然と役立ちますが、そうではないようです。
ジム

これは実際にはプロパティを設定しませんが、グローバルスコープ(つまり、)で変数をwindow.jQuery定義することにより、値を設定します。これにより、コードで定義されたウィンドウオブジェクトのプロパティセッター関数がトリガーされます。jQuerywindow
プロテクター1

このコードが実行される前にjQueryプロパティが定義されている場合、これは機能しません。つまり、このコードがロードされる前に遅延jquery.jsがロードされた場合。1つの解決策は、延期されたjquery.jsを前では</body>なく前に置くことです</head>
user36388

@user:jQuery(遅延またはその他)がロードされる前にコードを実行するだけです。どこにロードするかは問題ではなく、私のコードフラグメントがその前に来るだけです。
プロテクター1

1
これを使用するスクリプトがドキュメントにjQueryを含める前に来ることが保証できる場合、これは非常に便利です。上記のループアプローチによる非効率性や競合のシナリオはありません。
RedYetiCo

4

使用する:

$(document).ready(function() {
    // put all your jQuery goodness in here.
});

詳しくはこちらをご覧ください:http : //www.learningjquery.com/2006/09/introducing-document-ready

注:JQueryライブラリのスクリプトインポートがこの呼び出しより上にある限り、これは機能します。

更新:

なんらかの理由でコードが同期で読み込まれていない場合(私はこれに遭遇しことはありませんが、明らかに以下のコメントから可能である可能性があります)、次のようにコーディングできます。

function yourFunctionToRun(){
    //Your JQuery goodness here
}

function runYourFunctionWhenJQueryIsLoaded() {
    if (window.$){
        //possibly some other JQuery checks to make sure that everything is loaded here

        yourFunctionToRun();
    } else {
        setTimeout(runYourFunctionWhenJQueryIsLoaded, 50);
    }
}

runYourFunctionWhenJQueryIsLoaded();

6
この待機は、domが準備されるまでであり、jqueryがロードされるまでではありません。彼はおそらくCDNから2つのスクリプトファイル、1を持っている(Googleのjqueryの、ローカルにプラグイン)1が他よりも先にロードされている....プラグインが速くjQueryの自体よりもロードされている場合は、これを解決しないあなたのコード
サンダー

2
私はあなたに同意しません@Sanderこれは読み込みが同期しているので機能するはずです
malko

あなたが正しい、それらが異なるドメインからのものである場合に非同期でロードされるという私の仮定は完全に間違っています!すみません
サンダー

jqueryが利用できない場合、これにより例外がスローされ、elseステートメントに表示されないように見えます。それは試行錯誤か何かであると思います。
Sam Stoelinga

@SamStoelinga:ありがとう、これは修正されるはずです。
Briguy37

3

私はインターバルのものが好きではありません。jquery、または実際には何かを延期したい場合、通常は次のようになります。

皮切りに:

<html>
 <head>
  <script>var $d=[];var $=(n)=>{$d.push(n)}</script>
 </head>

次に:

 <body>
  <div id="thediv"></div>

  <script>
    $(function(){
       $('#thediv').html('thecode');
    });
  </script>

  <script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>

そして最後に:

  <script>for(var f in $d){$d[f]();}</script>
 </body>
<html>

または、あまり気が遠くなるようなバージョン:

<script>var def=[];function defer(n){def.push(n)}</script>
<script>
defer(function(){
   $('#thediv').html('thecode');
});
</script>
<script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<script>for(var f in def){def[f]();}</script>

また、非同期の場合、jquery onloadでプッシュされた関数を実行できます。

<script async onload="for(var f in def){def[f]();}" 
src="jquery.min.js" type="text/javascript"></script>

または:

function loadscript(src, callback){
  var script = document.createElement('script');
  script.src = src
  script.async = true;
  script.onload = callback;
  document.body.appendChild(script);
};
loadscript("jquery.min", function(){for(var f in def){def[f]();}});

2

それはあなたの問題ではないと思います。スクリプトの読み込みはデフォルトで同期しているため、defer属性を使用するか、別のAJAXリクエストを介してjQuery自体を読み込む場合を除いて、問題はおそらく404のようなものです。マークアップを表示できますか。ファイアバグまたはウェブインスペクター?


2

defer()Darioから拡張して、より再利用できるようにします。

function defer(toWaitFor, method) {
    if (window[toWaitFor]) {
        method();
    } else {
        setTimeout(function () { defer(toWaitFor, method) }, 50);
    }
}

次に実行されます:

function waitFor() {
    defer('jQuery', () => {console.log('jq done')});
    defer('utag', () => {console.log('utag done')});
}

1

これをチェックして:

https://jsfiddle.net/neohunter/ey2pqt5z/

これは、jqueryのonloadメソッドを使用できるようにする偽のjQueryオブジェクトを作成し、jqueryがロードされるとすぐに実行されます。

それは完璧ではありません。

// This have to be on <HEAD> preferibly inline
var delayed_jquery = [];
jQuery = function() {
  if (typeof arguments[0] == "function") {
    jQuery(document).ready(arguments[0]);
  } else {
    return {
      ready: function(fn) {
        console.log("registering function");
        delayed_jquery.push(fn);
      }
    }
  }
};
$ = jQuery;
var waitForLoad = function() {
  if (typeof jQuery.fn != "undefined") {
    console.log("jquery loaded!!!");
    for (k in delayed_jquery) {
      delayed_jquery[k]();
    }
  } else {
    console.log("jquery not loaded..");
    window.setTimeout(waitForLoad, 500);
  }
};
window.setTimeout(waitForLoad, 500);
// end



// now lets use jQuery (the fake version)
jQuery(document).ready(function() {
  alert('Jquery now exists!');
});

jQuery(function() {
  alert('Jquery now exists, this is using an alternative call');
})

// And lets load the real jquery after 3 seconds..
window.setTimeout(function() {
  var newscript = document.createElement('script');
  newscript.type = 'text/javascript';
  newscript.async = true;
  newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js';
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(newscript);
}, 3000);


これはドキュメント準備機能のおかげを登録するためのノー面倒ソリューションです
zanedev

0

上の接線方向のノートはここでその負荷の使用に近づきますsetTimeoutsetInterval。これらの場合、チェックが再度実行されると、DOMが既に読み込まれ、ブラウザーのDOMContentLoadedイベントが発生している可能性があるため、これらのアプローチを使用してそのイベントを確実に検出することはできません。私が見つけたのは、jQueryはreadyまだ機能しているので、いつものように埋め込むことができます

jQuery(document).ready(function ($) { ... }

setTimeoutまたは内部では、setIntervalすべてが正常に動作するはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.