JQuery yüklenene kadar komut dosyası yürütme işlemi nasıl yapılır


106

Sayfanın o kadar hızlı yüklenmesiyle ilgili bir sorun yaşıyorum ki jquery, sonraki bir komut dosyası tarafından çağrılmadan önce yüklemeyi bitirmedi. JQuery varlığını kontrol etmenin bir yolu var mı ve yoksa, bir süre bekleyip tekrar deneyin mi?


Aşağıdaki cevaplara / yorumlara yanıt olarak, işaretlemelerin bir kısmını gönderiyorum.

Durum ... asp.net ana sayfası ve alt sayfası.

Ana sayfada jquery için bir referansım var. Daha sonra içerik sayfasında, sayfaya özel komut dosyasına bir referansım var. Sayfaya özgü komut dosyası yüklenirken "$ tanımsız" olduğundan şikayet eder.

Şeylerin ateşlenme sırasını görmek için işaretlemede birkaç noktaya uyarılar koydum ve şu sırayla ateşlendiğini onayladım:

  1. Ana sayfa başlığı.
  2. Alt sayfa içerik bloğu 1 (ana sayfanın başlığının içinde bulunur, ancak ana sayfa komut dosyaları çağrıldıktan sonra).
  3. Alt sayfa içerik bloğu 2.

İşte ana sayfanın üst kısmındaki işaretleme:

<%@ 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>

Daha sonra ana sayfanın gövdesinde ek bir ContentPlaceHolder bulunur:

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

Alt sayfada şöyle görünür:

<%@ 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" dosyasının içeriği şu şekildedir:

    $(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
kullanıyor $(document).ready(function(){...});musun
rownage

Basit <script src="...">etiketlere sahip komut dosyaları yüklüyorsanız , bu gerçekleşemez. RequireJS veya LABjs gibi bir şey mi kullanıyorsunuz?
Pointy

$(document).ready()veya içinde sonraki komut dosyasını mı çalıştırıyorsunuz $(window).load()? Bir örnek görebilir miyiz?
John Hartsock

1
@AmandaMyer şimdi, belge hazır kullanımıyla ilgili tüm önerileri görmezden gelin, çünkü zaten bunu yapıyorsunuz, ancak bahse girerim eşzamanlı olarak yüklenmemelerine neden olan mime tipidir
Sander

2
Değiştirmeyi deneyin type="text/Scripts"için type="text/javascript"ya hep birlikte artık gerekli değil ondan kurtulmak, ayrıca kurtulmak language="javascript. Bir şeyler denemeye başlasan iyi olur.
Jack

Yanıtlar:


11

Düzenle

Komut dosyası etiketleriniz için doğru türü deneyebilir misiniz? text/ScriptsJavascript için doğru mime türü olmayan kullandığınızı görüyorum .

Bunu kullan:

<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>

düzenlemeyi bitir

veya javascript kodunuz için bir yükleyici olan require.js'ye bir göz atabilirsiniz .

projenize bağlı olarak, bu biraz fazla olabilir


205

Partiye geç ve Briguy37'nin sorusuna benzer şekilde, ancak ileride başvurmak için aşağıdaki yöntemi kullanıyorum ve jQuery yüklenene kadar ertelemek istediğim işlevleri geçiyorum:

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

Var olana kadar her 50 ms'de bir özyinelemeli olarak erteleme yöntemini çağırır, window.jQuerybu zamanda çıkar ve çağırır.method()

Anonim bir işleve sahip bir örnek:

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

2
Bu benim için işe yaramadı. Yöntemin içinde, $ tanımlanmadı ... neden olduğundan emin değilim.
Aaron Lifshin

Bu, Adobe Muse'da başka biri tarafından tasarlanan bir sitede bazı özel kodların çalışması için güzel bir çözümdü.
Buggabill

@gidim Olmaz, çünkü bu bir döngü değil bir zamanlayıcıdır. Ancak kullanıcı sayfada kaldığı sürece çalışmaya devam edecektir.
Micros

Komut dosyalarının yüklenme sırasını araştırmak daha iyi olacaktır. scriptJQuery'yi yükleyen etiketin bir deferözniteliği varsa, kod tanımlı betik sırasına rağmen daha sonra yüklenmeyerek soruna neden olacağını buldum .
ADTC

19

komut dosyasını gerçekten sona yüklemek için defer niteliğini kullanabilirsiniz.

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

ancak normalde komut dosyanızı doğru sırayla yüklemek işe yarayacaktır, bu nedenle jquery eklemeyi kendi komut dosyanızın önüne koyduğunuzdan

Kodunuz sayfadaysa ve ayrı bir js dosyasında değilse, bu nedenle komut dosyanızı yalnızca belge hazır olduktan sonra çalıştırmanız gerekir ve kodunuzu şu şekilde sarmalamak da çalışmalıdır:

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

Tek bir bağımlılığınız olduğu sürece sorun değil
Guillaume Massé

17

Darbio'nun erteleme yöntemi daha esnek olsa da, bunu yapmanın başka bir yolu.

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

16

en kolay ve en güvenli yol şuna benzer bir şey kullanmaktır:

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

        // place your code here.

        clearInterval(waitForJQuery);
    }
}, 10);

2
Dahi çözüm. Teşekkürler
Diego Fortes

13

Onload olayını deneyebilirsiniz. Tüm komut dosyaları yüklendiğinde yükseltildi:

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

Ancak, window.onload kullanarak başka komut dosyalarını geçersiz kılabileceğinizi unutmayın.


bu işe yarıyor, ancak jquery'niz sayfanın görünümünü değiştirirse, muhtemelen bir stil uygulanmamış içerik flaşı göreceksiniz
Matthew Lock

2
Diğer komut dosyalarının geçersiz
kılınmasını

@rogerdpack katılıyor, daha iyi bir çözüm.
Nigrimmist

10

Önerilen çözümün yalnızca eşzamansız kodla ilgilenirken çalıştığını buldum. Her iki durumda da işe yarayacak sürüm şu şekildedir:

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

Teşekkürler, yükte bir kez kontrol etmek ve yalnızca her 50 ms'de bir geri dönüş başlangıcı döngüsünü kontrol etmek, en çok oylanan yanıt gibi setInterval ile döngüye girmesine izin vermekten çok daha iyidir. En iyi durumda, en iyi cevabın ortalama 25 ms'lik durumu yerine 0 ms'lik bir gecikme yaşarsınız.
Luc

Güzel ve zarif - loadİşlevi geçme şeklinizi seviyorum ama sonra tekrar kullanıyorum setTimeout.
Nemesarial

6

Bu yaygın bir sorundur, harika bir PHP şablon oluşturma motoru kullandığınızı hayal edin, böylece temel düzeniniz var:

HEADER
BODY ==> dynamic CONTENT/PAGE
FOOTER

Ve tabii ki, bir yerde Javascript'i sayfanın en altına yüklemenin daha iyi olduğunu okursunuz, böylece dinamik içeriğiniz jQuery'nin (veya $) kim olduğunu bilmez.

Ayrıca bir yerde küçük Javascript'i satır içi yapmak iyidir, bu yüzden bir sayfada jQuery'ye ihtiyacınız olduğunu hayal edin, baboom, $ tanımlı değil (.. henüz ^^).

Facebook'un sağladığı çözümü seviyorum

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

Yani tembel bir programcı olarak (iyi bir programcı söylemeliyim ^^), bir eşdeğerini kullanabilirsiniz (sayfanızda):

window.jqReady = function() {}

Ve jQuery şunları içerdikten sonra düzeninizin altına ekleyin

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

Teşekkürler! Karşılaştığım durum tam olarak bu.
KumZ

Veya jquery yükünü en üste taşıyın :) stackoverflow.com/a/11012073/32453
rogerdpack

5

"Beklemek" yerine (genellikle kullanılarak yapılır setTimeout), jQuery nesnesinin pencerede tanımlanmasını, ona dayanan kodunuzu yürütmek için bir kanca olarak da kullanabilirsiniz. Bu, kullanılarak tanımlanan bir özellik tanımı yoluyla elde edilebilir 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 gerçekten bir pencere özelliği tanımlamışsa, ancak öyle görünmüyorsa, bu belirsiz bir şekilde yararlı olacaktır?
Jim

Gerçekten bir özellik ayarlamaz, ancak değişkeni genel kapsamda (yani ) window.jQuerytanımlayarak bir değere ayarlar . Bu, kodda tanımlanan pencere nesnesinde özellik belirleyici işlevini tetikleyecektir. jQuerywindow
Koruyucu 1

JQuery özelliği bu kod çalıştırılmadan önce tanımlanırsa bu çalışmaz; Örneğin, ertelenmiş jquery.js bu kod yüklenmeden önce yüklenirse. Bir çözüm, ertelenmiş jquery.js kodunuzu öncesine </body>değil öncesine </head>
koymaktır

@user: Kodu jQuery (ertelenmiş veya başka türlü) yüklenmeden önce çalıştırın. Nereye yüklediğiniz önemli değil, sadece kod parçam ondan önce geliyor.
Protector bir

1
Bunu kullanan komut dosyalarının belgenize jQuery eklenmeden önce geleceğini garanti edebiliyorsanız, bu çok kullanışlıdır. Yukarıdaki döngüdeki verimsizliklerin veya yarış durumu senaryolarının hiçbiri de yaklaşmıyor.
RedYetiCo

4

Kullanım:

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

Daha fazla bilgi için buna göz atın: http://www.learningjquery.com/2006/09/introducing-document-ready

Not: Bu, JQuery kitaplığınız için komut dosyası içe aktarımı bu çağrının üzerinde olduğu sürece çalışmalıdır.

Güncelleme:

Herhangi bir nedenle kodunuz eşzamanlı olarak yüklenmiyorsa ( hiç karşılaşmadım, ancak görünüşe göre aşağıdaki yorumdan mümkün olabilir), aşağıdaki gibi kodlayabilirsiniz.

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
bu bekleme dom hazır olana kadar, jquery yüklenene kadar değil. Muhtemelen biri bir CDN'den (google'dan jquery ve yerel olarak bir eklenti) olmak üzere 2 komut dosyası vardır ve burada 1 diğerinden daha önce yüklenir .... eklenti jquery'nin kendisinden daha hızlı yüklenirse kodunuz bunu çözmez
Sander

2
sana katılmıyorum @Sander, yükleme eşzamanlı olduğundan bu çalışmalı
malko

haklısınız, farklı bir etki alanından geliyorlarsa, eşzamansız olarak yüklenmeleri hakkındaki varsayım tamamen yanlıştır! bunun için özür dilerim
Sander

Bu, jquery kullanılamıyorsa, göründüğü gibi asla başka ifadeye girmemesine neden olan bir istisna atar. Sanırım bu bir deneme ve yakalama falan olmalı.
Sam Stoelinga

@SamStoelinga: Teşekkürler, bu şimdi düzeltilmelidir.
Briguy37

3

Aralıklı şeylere pek düşkün değilim. Jquery'yi veya herhangi bir şeyi ertelemek istediğimde, genellikle böyle bir şey olur.

İle başla:

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

Sonra:

 <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>

En sonunda:

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

Veya daha az akıllara durgunluk veren versiyon:

<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>

Ve zaman uyumsuz olması durumunda, itilen işlevleri jquery onload'da çalıştırabilirsiniz.

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

Alternatif olarak:

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]();}});

3

defer()Dario'dan daha yeniden kullanılabilir hale gelelim .

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

Hangisi daha sonra çalıştırılır:

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

2

Bunun senin sorunun olduğunu sanmıyorum. Komut dosyası yükleme varsayılan olarak eşzamanlıdır, bu nedenle deferözniteliği kullanmadığınız veya jQuery'nin kendisini başka bir AJAX isteği aracılığıyla yüklemediğiniz sürece , sorununuz muhtemelen daha çok 404'e benzer. kundakçı mı yoksa web müfettişi mi?


1

Şuna göz at:

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

Jquery'nin onload yöntemlerini kullanmanıza izin veren sahte bir jQuery nesnesi oluşturacak ve jquery yüklenir yüklenmez çalıştırılacaktır.

Mükemmel değil.

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


bu, belgeye hazır işlevleri kaydetmek için sorunsuz bir çözümdür teşekkürler
zanedev

0

Buradaki yaklaşımlara ilişkin teğetsel bir not setTimeoutveya setInterval. Bu durumlarda, kontrolünüz tekrar çalıştığında, DOM zaten yüklenmiş olabilir ve tarayıcının DOMContentLoadedolayı tetiklenmiş olabilir, bu nedenle bu yaklaşımları kullanarak bu olayı güvenilir bir şekilde tespit edemezsiniz. Bulduğum şey, jQuery'nin readyhala çalıştığı, böylece her zamanki gibi

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

içinde setTimeoutveya setIntervalher şey normal çalışmalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.