komut dosyalarını eşzamansız olarak yükle


125

JQuery'den birkaç eklenti, özel widget ve diğer bazı kitaplıkları kullanıyorum. sonuç olarak birkaç .js ve .css dosyam var. Sitem için bir yükleyici oluşturmam gerekiyor çünkü yüklenmesi biraz zaman alıyor. Yükleyicinin tümünü içe aktarmadan önce görüntüleyebilirsem iyi olur:

<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/myFunctions.js"></script>
<link type="text/css" href="css/main.css" rel="stylesheet" />
... 
....
 etc

Bir JavaScript kitaplığını eşzamansız olarak içe aktarmamı sağlayan birkaç öğretici buldum. örneğin şöyle bir şey yapabilirim:

  (function () {
        var s = document.createElement('script');
        s.type = 'text/javascript';
        s.async = true;
        s.src = 'js/jquery-ui-1.8.16.custom.min.js';
        var x = document.getElementsByTagName('script')[0];
        x.parentNode.insertBefore(s, x);
    })();

bazı nedenlerden dolayı tüm dosyalarım için aynı şeyi yaptığımda sayfalar çalışmıyor. Uzun zamandır sorunun nerede olduğunu bulmaya çalışıyorum ama bulamıyorum. İlk önce bunun muhtemelen bazı javascript işlevlerinin diğerlerine bağlı olmasından kaynaklandığını düşündüm. ancak zaman aşımı işlevini kullanarak onları doğru sırada yükledim, bir sonrakine geçtim ve sayfa hala garip davranıyor. örneğin bağlantılara tıklayamıyorum vs ... animasyonlar yine de çalışıyor ..

Neyse

İşte düşündüğüm şey şu ... Tarayıcıların bir önbelleği olduğuna inanıyorum, bu yüzden sayfanın ilk kez yüklenmesi uzun zaman alıyor ve bir dahaki sefere hızlı. bu yüzden yapmayı düşündüğüm şey, index.html sayfamı, tüm bu dosyaları eşzamansız olarak yükleyen bir sayfayla değiştirmek. ajax tüm bu dosyaları yüklemeyi bitirdiğinde kullanmayı planladığım sayfaya yönlendiriyor. Bu sayfayı kullanırken, dosyaların tarayıcının önbelleğine dahil edilmesi gerektiğinden yüklenmesi uzun sürmemelidir. indeks sayfamda (.js ve .css dosyasının eşzamansız olarak yüklendiği sayfa) Hata alma umurumda değil. Sadece bir yükleyici görüntüleyeceğim ve bittiğinde sayfayı yeniden yönlendireceğim ...

Bu fikir iyi bir alternatif mi? yoksa eşzamansız yöntemleri uygulamaya devam etmeli miyim?


DÜZENLE

her şeyi eşzamansız yükleme şeklim şuna benzer:

importScripts();

function importScripts()
{
    //import: jquery-ui-1.8.16.custom.min.js
    getContent("js/jquery-1.6.2.min.js",function (code) {
                var s = document.createElement('script');
                s.type = 'text/javascript';
                //s.async = true;
                s.innerHTML=code;
                var x = document.getElementsByTagName('script')[0];
                x.parentNode.insertBefore(s, x);
                setTimeout(insertNext1,1);
            });


    //import: jquery-ui-1.8.16.custom.min.js
    function insertNext1()
    {
        getContent("js/jquery-ui-1.8.16.custom.min.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext2,1);
                });
    }

    //import: jquery-ui-1.8.16.custom.css
    function insertNext2()
    {

        getContent("css/custom-theme/jquery-ui-1.8.16.custom.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext3,1);
                });
    }

    //import: main.css
    function insertNext3()
    {

        getContent("css/main.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext4,1);
                });
    }

    //import: jquery.imgpreload.min.js
    function insertNext4()
    {
        getContent("js/farinspace/jquery.imgpreload.min.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext5,1);
                });
    }


    //import: marquee.js
    function insertNext5()
    {
        getContent("js/marquee.js",function (code) {
                    var s = document.createElement('script');
                    s.type = 'text/javascript';
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext6,1);
                });
    }


    //import: marquee.css
    function insertNext6()
    {

        getContent("css/marquee.css",function (code) {
                    var s = document.createElement('link');
                    s.type = 'text/css';
                    s.rel ="stylesheet";
                    s.innerHTML=code;
                    var x = document.getElementsByTagName('script')[0];
                    x.parentNode.insertBefore(s, x);
                    setTimeout(insertNext,1);
                });
    }



    function insertNext()
    {
        setTimeout(pageReadyMan,10);        
    }
}


// get the content of url and pass that content to specified function
function getContent( url, callBackFunction )
{
     // attempt to create the XMLHttpRequest and make the request
     try
     {
        var asyncRequest; // variable to hold XMLHttpRequest object
        asyncRequest = new XMLHttpRequest(); // create request object

        // register event handler
        asyncRequest.onreadystatechange = function(){
            stateChange(asyncRequest, callBackFunction);
        } 
        asyncRequest.open( 'GET', url, true ); // prepare the request
        asyncRequest.send( null ); // send the request
     } // end try
     catch ( exception )
     {
        alert( 'Request failed.' );
     } // end catch
} // end function getContent

// call function whith content when ready
function stateChange(asyncRequest, callBackFunction)
{
     if ( asyncRequest.readyState == 4 && asyncRequest.status == 200 )
     {
           callBackFunction(asyncRequest.responseText);
     } // end if
} // end function stateChange

ve işin tuhaf yanı, stilin tüm çalışması artı tüm javascript işlevleri. sayfa bazı nedenlerden dolayı donmuş olsa da ...

Yanıtlar:


176

Eşzamansız yükleme için birkaç çözüm:

//this function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
  var s,
      r,
      t;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentNode.insertBefore(s, t);
}

Sayfada zaten jQuery varsa, şunu kullan:

$.getScript(url, successCallback)*

Ek olarak, komut dosyalarınızın belge yüklenmeden önce yüklenmesi / yürütülmesi mümkündür, bu da document.readyolayların öğelere bağlanabilmesi için beklemeniz gerektiği anlamına gelir .

Kodu görmeden sorunun tam olarak ne olduğunu söylemek mümkün değildir.

En basit çözüm, tüm komut dosyalarınızı sayfanın alt kısmında satır içinde tutmaktır, böylece çalıştırılırken HTML içeriğinin yüklenmesini engellemezler. Ayrıca, gerekli her komut dosyasını eşzamansız olarak yükleme zorunluluğunu da ortadan kaldırır.

Her zaman kullanılmayan ve bir tür daha büyük bir komut dosyası gerektiren özellikle süslü bir etkileşiminiz varsa, gerekli olana kadar bu belirli komut dosyasını yüklemekten kaçınmak yararlı olabilir (tembel yükleme).

* ile yüklenen komut dosyaları $.getScriptbüyük olasılıkla önbelleğe alınmayacaktır


PromiseNesne gibi modern özellikleri kullanabilen herkes için loadScriptişlev önemli ölçüde daha basit hale geldi:

function loadScript(src) {
    return new Promise(function (resolve, reject) {
        var s;
        s = document.createElement('script');
        s.src = src;
        s.onload = resolve;
        s.onerror = reject;
        document.head.appendChild(s);
    });
}

callbackDöndürülen söz geri aramayı ele alacağından , bu sürümün artık bir bağımsız değişken kabul etmediğini unutmayın . Önceden ne loadScript(src, callback)olurdu şimdi olacaktı loadScript(src).then(callback).

Bu, arızaları tespit edip idare edebilme gibi ek bir avantaja sahiptir, örneğin biri arayabilir ...

loadScript(cdnSource)
    .catch(loadScript.bind(null, localSource))
    .then(successCallback, failureCallback);

... ve CDN kesintilerini zarif bir şekilde halledecekti.


Bunu denemeye başlamak üzereyim. ancak, sayfayı farklı bir sayfaya yönlendirdiğimde bu komut dosyalarını farklı bir sayfaya yüklersem ve bu sayfanın aynı komut dosyalarına sahip olması durumunda yüklenmesi zaman almamalıdır. önbellekte olmalılar değil mi? öyleyse onun yerine o tekniği uygulamalı mıyım?
Tono Nam

1
Alt etiketi body yerine baş etiketine ekledim ve değiştirdim ... ..var x = document.getElementsByTagName ('head') [0]; x.appendChild (s);
Tono Nam

1
@TonoNam, kullanabilirsiniz document.head.appendChild, ancak komut dosyası eklemeyle ilgili bazı niş sorunlar vardır <head>; komut dosyalarının yüklenmesini ve yürütülmesini engelleyecek hiçbir şey.
zzzzBov

1
T.parentNode.insertBefore kullanmak zorunda kaldım (t.parent yerine).
Phil LaNasa

1
@MuhammadUmer, document.writebelge yüklenmeden önce ek bir komut dosyası etiketi yazıyorsanız , komut dosyası sayfanın yüklenmesinin bir parçası olarak eşzamanlı olarak çalıştırılır ve kendi başına herhangi bir eşzamansız geri arama davranışı içermez. Bir komut dosyası öğesi oluşturuyor ve bunu sayfaya ekliyorsanız, eşzamansız olarak tetiklemek için olay dinleyicileri ekleme erişiminiz olur. tl; dr: komut dosyasını JS ile nasıl yüklediğinize bağlıdır.
zzzzBov

33

HTML5'in yeni "eşzamansız" özniteliğinin hile yapması bekleniyor. IE'yi önemsiyorsanız çoğu tarayıcıda 'erteleme' de desteklenir.

eşzamansız - HTML

<script async src="siteScript.js" onload="myInit()"></script>

erteleme - HTML

<script defer src="siteScript.js" onload="myInit()"></script>

Yeni adsense reklam birimi kodunu analiz ederken, özniteliğin farkına vardım ve bir arama beni buraya yönlendiriyor: http://davidwalsh.name/html5-async


stackoverflow.com/questions/2774373/… 'yi okuduktan sonra anladığım kadarıyla , asyn yükleme için değil, içerdiği javascript'in ne zaman çalıştırılacağını belirlemek içindir.
JackDev

9
Erteleme özelliği, tarayıcının komut dosyasının yürütülmesini belge yüklenip ayrıştırılıp değiştirilmeye hazır olana kadar ertelemesine neden olur. Zaman uyumsuz nitelik, tarayıcının komut dosyasını olabildiğince çabuk çalıştırmasına, ancak komut dosyası indirilirken belgenin ayrıştırılmasını engellememesine neden olur
shuseel

1
"asyn yükleme için değil, içerdiği javascript'in ne zaman çalıştırılacağını belirlemek içindir" Bu çelişkili değildir; Her durumda, tarayıcı komut dosyasını en kısa sürede yüklemeye başlayacaktır. Ancak olmadan async veya deferyüklenmeden oluşturmayı engelleyecektir. Ayar async, komut dosyasını ASAP engellememesini ve çalıştırmamasını söyleyecektir. Ayar defer, ona engellememesini söyleyecektir, ancak sayfa tamamlanana kadar komut dosyasını çalıştırmayı bekleyecektir . Bağımlılıkları olmadığı sürece komut dosyalarını en kısa sürede çalıştırmak genellikle sorun değildir (örneğin jQuery). Bir komut dosyasının diğerine bağımlılıkları varsa, onLoadonu beklemek için kullanın .
Stijn de Witt

@StijndeWitt Ne zaman uyumsuz ne de erteleme belirtilmemişse?
Muhammed Shareef C

@MohammedShareefC İkisini de belirtmezseniz, eşitleme davranışına çok benzeyen bir şey elde edersiniz; tarayıcı, komut dosyasını indirirken ve çalıştırırken daha fazla işlemeyi engeller. Dolayısıyla, varsayılan davranış eşitlemedir. Ancak bu performans açısından zararlı olduğu için tarayıcılar ellerinden geldiğince bunun etrafında çalışacaktır. CSS'nin ayrıştırılması, yüklenmesi ve uygulanması vb. İle devam edebilirler ... Ancak bir sonraki komut dosyası parçasını çalıştırmaya başlayamazlar. Yani şeyler engellenecek. Zaman uyumsuz olarak ayarlayarak, tarayıcıya devam etmenin uygun olduğunu söylüyorsunuz ve bunu kendiniz çalıştırdığınızdan emin olacaksınız.
Stijn de Witt

8

Komut dosyalarını eşzamansız olarak yükledim (html 5 bu özelliğe sahiptir), yükleme bittiğinde tüm komut dosyaları, sayfayı index2.html'nin aynı kitaplıkları kullandığı index2.html'ye yönlendirdim. Tarayıcılar, sayfa index2.html'ye yeniden yönlendirildiğinde bir önbelleğe sahip olduğundan, index2.html, sayfayı yüklemek için gereken her şeye sahip olduğundan bir saniyeden daha kısa sürede yüklenir. İndex.html sayfamda, tarayıcının bu resimleri önbelleğe yerleştirmesi için kullanmayı planladığım resimleri de yüklüyorum. index.html dosyam şöyle görünür:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Project Management</title>

    <!-- the purpose of this page is to load all the scripts on the browsers cache so that pages can load fast from now on -->

    <script type="text/javascript">

        function stylesheet(url) {
            var s = document.createElement('link');
            s.type = 'text/css';
            s.async = true;
            s.src = url;
            var x = document.getElementsByTagName('head')[0];
            x.appendChild(s);
        }

        function script(url) {
            var s = document.createElement('script');
            s.type = 'text/javascript';
            s.async = true;
            s.src = url;
            var x = document.getElementsByTagName('head')[0];
            x.appendChild(s);
        }

        //load scritps to the catche of browser
        (function () {            
                stylesheet('css/custom-theme/jquery-ui-1.8.16.custom.css');
                stylesheet('css/main.css');
                stylesheet('css/marquee.css');
                stylesheet('css/mainTable.css');

                script('js/jquery-ui-1.8.16.custom.min.js');
                script('js/jquery-1.6.2.min.js');
                script('js/myFunctions.js');
                script('js/farinspace/jquery.imgpreload.min.js');
                script('js/marquee.js');            
        })();

    </script>

    <script type="text/javascript">
       // once the page is loaded go to index2.html
        window.onload = function () {
            document.location = "index2.html";
        }
    </script>

</head>
<body>

<div id="cover" style="position:fixed; left:0px; top:0px; width:100%; height:100%; background-color:Black; z-index:100;">Loading</div>

<img src="images/home/background.png" />
<img src="images/home/3.png"/>
<img src="images/home/6.jpg"/>
<img src="images/home/4.png"/>
<img src="images/home/5.png"/>
<img src="images/home/8.jpg"/>
<img src="images/home/9.jpg"/>
<img src="images/logo.png"/>
<img src="images/logo.png"/>
<img src="images/theme/contentBorder.png"/>

</body>
</html>

bununla ilgili bir başka güzel şey de, sayfaya bir yükleyici yerleştirebilirim ve sayfanın yüklenmesi bittiğinde yükleyici ortadan kalkacak ve birkaç milisaniye içinde yeni sayfa çalışmaya başlayacak.


1
@MohammedShareefC Bu ironi. Sadece öğeleri önceden yüklemek için özel bir sayfa, SEO açısından iyi bir fikir gibi görünmüyor. Önceden yükleme harika, ancak bunu başarmak için yeniden yönlendirmenize gerek yok. Bağlantıları gizli bir div'e yapıştırmanız yeterlidir; tarayıcı bunu sizin için otomatik olarak halleder. Sonra yeniden yönlendirmeyin, yalnızca gerçek sayfayı oluşturun. COPY-PASTERS BUNU OKUYUN : Lütfen bu HTML’den herhangi birini kullanmadan önce ISO-88591 kodlamasını UTF-8 olarak değiştirin, böylece geri kalanımız herhangi bir zamanda kodlamadan kurtulabiliriz. Teşekkürler!
Stijn de Witt

Lütfen yeni
cevabıma bakın

8

Google'dan örnek

<script type="text/javascript">
  (function() {
    var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    po.src = 'https://apis.google.com/js/plusone.js?onload=onLoadCallback';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
  })();
</script>

8

Birkaç not:

  • s.async = trueHTML5 doctype için pek doğru değil, doğru s.async = 'async'(aslında kullanmak true doğru , hemen aşağıdaki yorumda işaret eden amn sayesinde )
  • Siparişi kontrol etmek için zaman aşımlarını kullanmak çok iyi ve güvenli değildir ve ayrıca tüm zaman aşımlarının toplamına eşit olacak şekilde yükleme süresini çok daha uzatırsınız!

Dosyaları eşzamansız olarak yüklemek için yeni bir neden olduğundan, ancak sırayla, örneğinize göre biraz daha işlevsel odaklı bir yol öneriyorum ( console.logüretim kullanımı için kaldırın :)):

(function() {
    var prot = ("https:"===document.location.protocol?"https://":"http://");

    var scripts = [
        "path/to/first.js",
        "path/to/second.js",
        "path/to/third.js"
    ];

    function completed() { console.log('completed'); }  // FIXME: remove logs

    function checkStateAndCall(path, callback) {
        var _success = false;
        return function() {
            if (!_success && (!this.readyState || (this.readyState == 'complete'))) {
                _success = true;
                console.log(path, 'is ready'); // FIXME: remove logs
                callback();
            }
        };
    }

    function asyncLoadScripts(files) {
        function loadNext() { // chain element
            if (!files.length) completed();
            var path = files.shift();
            var scriptElm = document.createElement('script');
            scriptElm.type = 'text/javascript';
            scriptElm.async = true;
            scriptElm.src = prot+path;
            scriptElm.onload = scriptElm.onreadystatechange = \
                checkStateAndCall(path, loadNext); // load next file in chain when
                                                   // this one will be ready 
            var headElm = document.head || document.getElementsByTagName('head')[0];
            headElm.appendChild(scriptElm);
        }
        loadNext(); // start a chain
    }

    asyncLoadScripts(scripts);
})();

4
s.async = trueolduğu doğru . Özellik async, w3.org/TR/html5/scripting-1.html#attr-script-async adresindeki W3C'nin HTML 5 önerisinde açıkça bir boole olarak belirtilmiştir . DOM arayüzünü uygulayan nesneler tarafından sunulan async özellik ile özniteliği karıştırıyorsunuz . Nitekim, benzer bir şey aracılığıyla öğenin karşılık gelen özniteliğini değiştirirken, tüm HTML özniteliklerinin her şeyden önce metin olduğu için kullanmanız gerekir . asyncHTMLScriptElementElement.setAttributeelement.setAttribute("async", "async")
amn

"Dosyaları eşzamansız olarak yüklemek için yeni bir neden olduğundan, ancak sırayla, örneğinize göre biraz daha işlevsel odaklı bir yol öneriyorum [...]". Zaman uyumsuzluğunun genellikle "daha iyi" olduğunu biliyorum, ancak hangi "son" nedeni kastediyorsunuz?
BluE

'İf (! Files.length) tamamlandı ();' bir 'dönüş' ekleyerek: 'if (! files.length) {tamamlandı (); dönüş;} '
Fil

4

HTML5 sayesinde, artık etikete "eşzamansız" ekleyerek eşzamansız olarak yüklemek istediğiniz komut dosyalarını bildirebilirsiniz:

<script async>...</script>

Not: Async niteliği yalnızca harici komut dosyaları içindir (ve yalnızca src özelliği mevcutsa kullanılmalıdır).

Not: Harici bir komut dosyasının çalıştırılmasının birkaç yolu vardır:

  • Eşzamansız mevcutsa: Komut, sayfanın geri kalanıyla eşzamansız olarak yürütülür (sayfa ayrıştırmaya devam ederken komut dosyası çalıştırılır)
  • Eşzamansız yoksa ve erteleme mevcutsa: Komut, sayfa ayrıştırmayı bitirdiğinde çalıştırılır
  • Zaman uyumsuz veya erteleme yoksa: Komut dosyası, tarayıcı sayfayı ayrıştırmaya devam etmeden hemen getirilir ve yürütülür.

Şuna bakın: http://www.w3schools.com/tags/att_script_async.asp


2

ZzzzBov'un cevabını geri aramanın varlığını kontrol ederek tamamlar ve argümanların geçişine izin veririm:

    function loadScript(src, callback, args) {
      var s, r, t;
      r = false;
      s = document.createElement('script');
      s.type = 'text/javascript';
      s.src = src;
      if (typeof(callback) === 'function') {
        s.onload = s.onreadystatechange = function() {
          if (!r && (!this.readyState || this.readyState === 'complete')) {
            r = true;
            callback.apply(args);
          }
        };
      };
      t = document.getElementsByTagName('script')[0];
      t.parent.insertBefore(s, t);
    }

2

Eşzamansız betik yüklemesi için harika bir çağdaş çözüm, ancak yalnızca js betiğini async false ile ele alıyor .

Www.html5rocks.com'da yazılmış harika bir makale var - Komut dosyası yüklemenin karanlık sularına derinlemesine dalın .

Birçok olası çözümü değerlendirdikten sonra, yazar, js komut dosyaları tarafından sayfa oluşturmayı engellemekten kaçınmanın mümkün olan en iyi yol, gövde öğesinin sonuna js komut dosyaları eklemenin olduğu sonucuna varmıştır.

Bu arada yazar, komut dosyalarını eşzamansız olarak yüklemek ve yürütmek için çaresiz olan kişiler için başka bir iyi alternatif çözüm ekledi.

Adlandırılmış dört komut dosyası script1.js, script2.js, script3.js, script4.jsolduğunu düşünürsek, async = false uygulayarak bunu yapabilirsiniz :

[
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

Şimdi, Spec diyor : Birlikte indirin, tüm indirmelerden hemen sonra sırayla çalıştırın.

Firefox <3.6, Opera diyor ki: Bu “eşzamansız” şeyin ne olduğu hakkında hiçbir fikrim yok, ama öyle oluyor ki JS aracılığıyla eklenen komut dosyalarını eklendikleri sırayla çalıştırıyorum.

Safari 5.0 diyor ki: "zaman uyumsuz" u anlıyorum, ancak JS ile "yanlış" olarak ayarlamayı anlamıyorum. Senaryolarınızı yere iner inmez, hangi sırayla olursa olsun çalıştıracağım.

IE <10 diyor ki: "Async" hakkında hiçbir fikrim yok, ancak "onreadystatechange" kullanan bir geçici çözüm var.

Diğer her şey diyor ki: Ben senin arkadaşınım, bunu kitaba göre yapacağız.

Şimdi, IE <10 geçici çözümü ile tam kod:

var scripts = [
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && ( pendingScripts[0].readyState == 'loaded' || pendingScripts[0].readyState == 'complete' ) ) {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we’ll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

1

Komut dosyalarınızın bu kadar yavaş yüklenmesinin bir nedeni, sayfayı yüklerken tüm komut dosyalarınızı şu şekilde çalıştırıyor olmanızdır:

callMyFunctions();

onun yerine:

$(window).load(function() {
      callMyFunctions();
});

Bu ikinci komut dosyası biti, tarayıcı komut dosyalarınızdan herhangi birini çalıştırmaya başlamadan önce tüm Javascript kodunuzu tamamen yükleyene kadar bekler ve kullanıcıya sayfanın daha hızlı yüklendiğini gösterir.

Yükleme süresini azaltarak kullanıcı deneyimini geliştirmek istiyorsanız, "yükleme ekranı" seçeneğini tercih etmem. Bence bu, sayfanın daha yavaş yüklenmesinden çok daha can sıkıcı olurdu.


1

Modernizr'e bir göz atmanızı öneririm . Dosyanın yüklenip yüklenmediğini kontrol etmenize ve belirlediğiniz diğerinde komut dosyasını çalıştırmanıza olanak tanıyan özelliklerle javascript'inizi eşzamansız olarak yükleyebileceğiniz küçük, hafif bir kitaplık.

İşte jquery yüklemeye bir örnek:

Modernizr.load([
  {
    load: '//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js',
    complete: function () {
      if ( !window.jQuery ) {
            Modernizr.load('js/libs/jquery-1.6.1.min.js');
      }
    }
  },
  {
    // This will wait for the fallback to load and
    // execute if it needs to.
    load: 'needs-jQuery.js'
  }
]);

1

Bu konuda yardımcı olmak için küçük bir gönderi yazdım, buradan daha fazlasını okuyabilirsiniz https://timber.io/snippets/asynchronously-load-a-script-in-the-browser-with-javascript/ , ancak ekledim aşağıdaki yardımcı sınıf. Bunu yaptığında, bir komut dosyasının belirli bir pencere özniteliğini yüklemesini ve döndürmesini otomatik olarak bekleyecektir.

export default class ScriptLoader {
  constructor (options) {
    const { src, global, protocol = document.location.protocol } = options
    this.src = src
    this.global = global
    this.protocol = protocol
    this.isLoaded = false
  }

  loadScript () {
    return new Promise((resolve, reject) => {
      // Create script element and set attributes
      const script = document.createElement('script')
      script.type = 'text/javascript'
      script.async = true
      script.src = `${this.protocol}//${this.src}`

      // Append the script to the DOM
      const el = document.getElementsByTagName('script')[0]
      el.parentNode.insertBefore(script, el)

      // Resolve the promise once the script is loaded
      script.addEventListener('load', () => {
        this.isLoaded = true
        resolve(script)
      })

      // Catch any errors while loading the script
      script.addEventListener('error', () => {
        reject(new Error(`${this.src} failed to load.`))
      })
    })
  }

  load () {
    return new Promise(async (resolve, reject) => {
      if (!this.isLoaded) {
        try {
          await this.loadScript()
          resolve(window[this.global])
        } catch (e) {
          reject(e)
        }
      } else {
        resolve(window[this.global])
      }
    })
  }
}

Kullanım şu şekildedir:

const loader = new Loader({
    src: 'cdn.segment.com/analytics.js',
    global: 'Segment',
})

// scriptToLoad will now be a reference to `window.Segment`
const scriptToLoad = await loader.load()


0

Eh, x.parentNodeHEAD öğesini döndürür, bu nedenle komut dosyasını head etiketinin hemen öncesine eklersiniz. Belki sorun budur.

Onun x.parentNode.appendChild()yerine deneyin .



0

LABJS veya RequreJS kullanabilirsiniz

Gibi komut dosyası yükleyiciler LABJS, RequireJSkodunuzun hızını ve kalitesini artıracaktır.


0

Fetch Injection kullanmayı düşündünüz mü? Bu gibi durumları ele almak için fetch-inject adında açık kaynak bir kitaplık oluşturdum . Yükleyiciniz kitaplığı kullanırken şöyle görünebilir:

fetcInject([
  'js/jquery-1.6.2.min.js',
  'js/marquee.js',
  'css/marquee.css',
  'css/custom-theme/jquery-ui-1.8.16.custom.css',
  'css/main.css'
]).then(() => {
  'js/jquery-ui-1.8.16.custom.min.js',
  'js/farinspace/jquery.imgpreload.min.js'
})

Geriye dönük uyumluluk için özellik algılama ve XHR Enjeksiyonu veya Komut Dosyası DOM Öğelerine geri dönüşten yararlanın veya kullanarak etiketleri sayfaya satır içi yapın document.write.


0

Oluşturmayı engelleyen JavaScript'i ortadan kaldırmak için özel çözümüm:

// put all your JS files here, in correct order
const libs = {
  "jquery": "https://code.jquery.com/jquery-2.1.4.min.js",
  "bxSlider": "https://cdnjs.cloudflare.com/ajax/libs/bxslider/4.2.5/jquery.bxslider.min.js",
  "angular": "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js",
  "ngAnimate": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-animate.min.js"
}
const loadedLibs = {}
let counter = 0

const loadAsync = function(lib) {
  var http = new XMLHttpRequest()
  http.open("GET", libs[lib], true)
  http.onload = () => {
    loadedLibs[lib] = http.responseText
    if (++counter == Object.keys(libs).length) startScripts()
  }
  http.send()
}

const startScripts = function() {
  for (var lib in libs) eval(loadedLibs[lib])
  console.log("allLoaded")
}

for (var lib in libs) loadAsync(lib)

Kısacası, tüm komut dosyalarınızı eşzamansız olarak yükler ve ardından bunları sonuç olarak yürütür.

Github deposu : https://github.com/mudroljub/js-async-loader


1
ÇalışmazNo 'Access-Control-Allow-Origin' header is present on the requested resource
Avram


0

Örneğin birisi React'te kullanmak isterse küçük bir ES6 işlevi

import {uniqueId} from 'lodash' // optional
/**
 * @param {String} file The path of the file you want to load.
 * @param {Function} callback (optional) The function to call when the script loads.
 * @param {String} id (optional) The unique id of the file you want to load.
 */
export const loadAsyncScript = (file, callback, id) => {
  const d = document
  if (!id) { id = uniqueId('async_script') } // optional
  if (!d.getElementById(id)) {
    const tag = 'script'
    let newScript = d.createElement(tag)
    let firstScript = d.getElementsByTagName(tag)[0]
    newScript.id = id
    newScript.async = true
    newScript.src = file
    if (callback) {
      // IE support
      newScript.onreadystatechange = () => {
        if (newScript.readyState === 'loaded' || newScript.readyState === 'complete') {
          newScript.onreadystatechange = null
          callback(file)
        }
      }
      // Other (non-IE) browsers support
      newScript.onload = () => {
        callback(file)
      }
    }
    firstScript.parentNode.insertBefore(newScript, firstScript)
  } else {
    console.error(`The script with id ${id} is already loaded`)
  }
}


-3

Önce dosyaları küçültmeyi ve bunun size yeterince büyük bir hız artışı sağlayıp sağlamadığını görmenizi öneririm. Sunucunuz yavaşsa, bu statik içeriği bir CDN'ye koymayı deneyebilirsiniz.

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.