memuat skrip secara asinkron

125

Saya menggunakan beberapa plugin, widget khusus, dan beberapa pustaka lain dari JQuery. sebagai hasilnya saya memiliki beberapa file .js dan .css. Saya perlu membuat loader untuk situs saya karena perlu beberapa waktu untuk memuat. alangkah baiknya jika saya dapat menampilkan loader sebelum mengimpor semua:

<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

Saya telah menemukan beberapa tutorial yang memungkinkan saya mengimpor pustaka JavaScript secara asinkron. misalnya saya bisa melakukan sesuatu seperti:

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

untuk beberapa alasan ketika saya melakukan hal yang sama untuk semua file saya, halaman tidak berfungsi. Saya telah berusaha begitu lama untuk mencoba menemukan di mana masalahnya tetapi saya tidak dapat menemukannya. Pertama saya pikir itu mungkin karena beberapa fungsi javascript bergantung pada yang lain. tetapi saya memuatnya dalam urutan yang benar menggunakan fungsi waktu habis ketika satu selesai saya melanjutkan dengan yang berikutnya dan halaman masih berperilaku aneh. misalnya saya tidak dapat mengklik tautan dll ... meskipun animasi masih berfungsi ..

Pokoknya

Inilah yang saya pikirkan ... Saya percaya browser memiliki cache, itulah sebabnya butuh waktu lama untuk memuat halaman untuk pertama kalinya dan kali berikutnya cepat. jadi yang saya pikirkan adalah mengganti halaman index.html saya dengan halaman yang memuat semua file ini secara asynchronous. ketika ajax selesai memuat semua file tersebut dialihkan ke halaman yang saya rencanakan untuk digunakan. saat menggunakan halaman itu seharusnya tidak membutuhkan waktu lama untuk memuat karena file-file tersebut harus sudah dimasukkan ke dalam cache browser. di halaman indeks saya (halaman tempat file .js dan .css dimuat secara asinkron), saya tidak peduli jika ada error. Saya hanya akan menampilkan loader dan mengarahkan halaman setelah selesai ...

Apakah ide ini alternatif yang bagus? atau haruskah saya terus mencoba menerapkan metode asynchronous?


EDIT

cara saya memuat semua asinkron seperti:

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

dan bagian yang aneh adalah bahwa semua gaya bekerja ditambah semua fungsi javascript. halaman dibekukan karena beberapa alasan ...

Tono Nam
sumber

Jawaban:

176

Beberapa solusi untuk pemuatan asinkron:

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

Jika Anda sudah memiliki jQuery di halaman, cukup gunakan:

$.getScript(url, successCallback)*

Selain itu, mungkin saja skrip Anda sedang dimuat / dijalankan sebelum dokumen selesai dimuat, yang berarti Anda harus menunggu document.readysebelum peristiwa dapat diikat ke elemen.

Tidak mungkin untuk mengetahui secara spesifik apa masalah Anda tanpa melihat kodenya.

Solusi paling sederhana adalah menjaga semua skrip Anda tetap sebaris di bagian bawah halaman, dengan cara itu skrip tidak memblokir pemuatan konten HTML saat dijalankan. Ini juga menghindari masalah karena harus memuat setiap skrip yang diperlukan secara asinkron.

Jika Anda memiliki interaksi yang sangat mewah yang tidak selalu digunakan yang memerlukan skrip yang lebih besar, sebaiknya hindari memuat skrip tertentu hingga diperlukan (pemuatan lambat).

* skrip yang dimuat $.getScriptkemungkinan besar tidak akan disimpan dalam cache


Bagi siapa pun yang dapat menggunakan fitur modern seperti Promiseobjek, loadScriptfungsinya menjadi jauh lebih sederhana:

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

Ketahuilah bahwa versi ini tidak lagi menerima callbackargumen karena janji yang dikembalikan akan menangani callback. Apa yang sebelumnya akan menjadi loadScript(src, callback)sekarang loadScript(src).then(callback).

Ini memiliki bonus tambahan untuk dapat mendeteksi dan menangani kegagalan, misalnya seseorang dapat memanggil ...

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

... dan itu akan menangani pemadaman CDN dengan anggun.

zzzzBov
sumber
Saya akan mulai mencobanya. tetapi jika saya memuat skrip tersebut di halaman yang berbeda saat saya mengarahkan halaman ke halaman lain dan halaman tersebut kebetulan memiliki skrip yang sama, mereka tidak perlu waktu untuk memuatnya. mereka seharusnya ada di cache kan? jadi bukankah saya harus menerapkan teknik itu?
Tono Nam
1
Saya mengubah dan menambahkan anak itu ke tag kepala alih-alih tubuh ... ..var x = document.getElementsByTagName ('head') [0]; x.appendChild (s);
Tono Nam
1
@TonoNam, Anda dapat menggunakan saja document.head.appendChild, namun ada beberapa masalah khusus dengan menambahkan skrip ke <head>; tidak ada yang dapat mencegah skrip dimuat dan dijalankan.
zzzzBov
1
Saya harus menggunakan t.parentNode.insertBefore (sebagai lawan t.parent).
Phil LaNasa
1
@MuhammadUmer, jika Anda menulis tag skrip tambahan document.writesebelum dokumen dimuat, skrip akan dijalankan secara sinkron sebagai bagian dari memuat laman, dan tidak akan menyertakan perilaku panggilan balik asinkron sendiri. Jika Anda membuat elemen skrip dan menambahkannya ke halaman, Anda akan memiliki akses untuk menambahkan event listener untuk memicu secara asinkron. tl; dr: itu tergantung bagaimana Anda memuat skrip dengan JS.
zzzzBov
33

Atribut 'async' baru HTML5 seharusnya melakukan trik. 'defer' juga didukung di sebagian besar browser jika Anda peduli dengan IE.

async - HTML

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

defer - HTML

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

Saat menganalisis kode unit iklan adsense baru, saya melihat atribut dan pencarian membawa saya ke sini: http://davidwalsh.name/html5-async

Donald Porter
sumber
dari pemahaman saya setelah membaca stackoverflow.com/questions/2774373/… , asyn bukan untuk memuat, tetapi untuk menentukan kapan harus menjalankan javascript yang terkandung.
JackDev
9
Atribut defer menyebabkan browser menunda eksekusi skrip sampai dokumen telah dimuat dan diurai dan siap untuk dimanipulasi. Atribut async menyebabkan browser menjalankan skrip sesegera mungkin tetapi tidak memblokir penguraian dokumen saat skrip sedang diunduh
shuseel
1
"asyn bukan untuk memuat, tapi untuk menentukan kapan harus menjalankan javascript yang ada" Ini tidak bertentangan; Dalam semua kasus, browser akan mulai memuat skrip secepatnya. Tapi tanpa async atau deferitu akan memblokir rendering saat dimuat. Pengaturan asyncakan memberitahukannya untuk tidak memblokir dan menjalankan skrip secepatnya. Pengaturan deferakan memberitahukannya untuk tidak memblokir tetapi menunggu dengan menjalankan skrip sampai halaman selesai. Biasanya tidak ada masalah untuk menjalankan skrip secepatnya selama mereka tidak memiliki dependensi (mis. JQuery). Jika satu skrip memiliki ketergantungan pada yang lain, gunakan onLoaduntuk menunggu.
Stijn de Witt
@StijndeWitt Bagaimana jika Tidak ada async atau penundaan yang ditentukan?
Mohammed Shareef C
@MohammedShareefC Jika Anda tidak menentukan keduanya, Anda akan mendapatkan sesuatu yang sangat mirip dengan perilaku sinkronisasi; browser memblokir pemrosesan lebih lanjut saat mendownload dan menjalankan skrip. Jadi secara efektif, perilaku default adalah sinkronisasi. Tetapi karena ini merusak kinerja, browser akan mengatasinya semaksimal mungkin. Mereka dapat melanjutkan dengan mem-parsing, memuat dan menerapkan CSS, dll ... Namun mereka tidak dapat mulai menjalankan fragmen skrip berikutnya. Jadi barang akan diblokir. Dengan menyetel async, Anda memberi tahu browser bahwa tidak apa-apa untuk melanjutkan dan Anda akan memastikan bahwa Anda membuatnya bekerja sendiri.
Stijn de Witt
8

Saya memuat skrip secara asinkron (html 5 memiliki fitur itu) ketika semua skrip selesai memuat, saya mengarahkan halaman ke index2.html di mana index2.html menggunakan perpustakaan yang sama. Karena browser memiliki cache setelah halaman dialihkan ke index2.html, index2.html dimuat dalam waktu kurang dari satu detik karena memiliki semua yang dibutuhkan untuk memuat halaman. Di halaman index.html saya juga memuat gambar yang saya rencanakan untuk digunakan sehingga browser menempatkan gambar-gambar itu di cache. jadi index.html saya terlihat seperti:

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

Hal menyenangkan lainnya tentang ini adalah saya dapat menempatkan loader di halaman dan ketika halaman selesai memuat loader akan hilang dan dalam hitungan milidetik halaman baru akan berjalan.

Tono Nam
sumber
1
@MohammedShareefC Ini ironi. Halaman khusus hanya untuk melakukan pramuat tidak terdengar seperti ide SEO yang bagus. Pramuat bagus, tetapi Anda tidak perlu mengarahkan ulang untuk mencapainya. Cukup tempelkan tautan di div tersembunyi dan browser akan menanganinya untuk Anda secara otomatis. Maka jangan redirect tetapi render saja halaman yang sebenarnya. COPY-PASTERS BACA INI : Ubah encoding ISO-88591 ke UTF-8 sebelum menggunakan HTML ini sehingga kita semua bisa keluar dari neraka encoding dalam waktu dekat. Terima kasih!
Stijn de Witt
Silakan lihat jawaban baru saya: stackoverflow.com/questions/7718935/load-scripts-asynchronously/…
asmmahmud
8

Contoh dari google

<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>
Kernel Med
sumber
8

Beberapa catatan:

  • s.async = truetidak terlalu benar untuk doctype HTML5, benar s.async = 'async'(sebenarnya menggunakan true benar , terima kasih kepada amn yang menunjukkannya di komentar di bawah)
  • Menggunakan batas waktu untuk mengontrol urutan tidak terlalu baik dan aman, dan Anda juga membuat waktu pemuatan jauh lebih besar, untuk menyamakan jumlah semua batas waktu!

Karena ada alasan baru-baru ini untuk memuat file secara asinkron, tetapi secara berurutan, saya akan merekomendasikan cara yang lebih berorientasi fungsional daripada contoh Anda (hapus console.loguntuk penggunaan produksi :)):

(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);
})();
shaman.sir
sumber
4
s.async = trueadalah benar . Properti asyncditentukan secara eksplisit sebagai boolean dalam rekomendasi HTML 5 W3C di w3.org/TR/html5/scripting-1.html#attr-script-async . Anda mengacaukan async atribut dengan asyncproperti yang diekspos oleh objek yang mengimplementasikan HTMLScriptElementantarmuka DOM. Memang, ketika memanipulasi atribut terkait dari elemen melalui sesuatu seperti Element.setAttribute, Anda harus menggunakan element.setAttribute("async", "async")karena semua atribut HTML adalah teks pertama dan terpenting.
amn
"Karena ada alasan baru-baru ini untuk memuat file secara asynchronous, tetapi secara berurutan, saya akan merekomendasikan cara yang lebih berorientasi fungsional daripada contoh Anda [...]". Saya tahu asinkron biasanya "lebih baik", tetapi alasan "terbaru" apa yang Anda maksud?
BluE
Saya mengubah 'if (! Files.length) complete ();' menambahkan 'return': 'if (! files.length) {complete (); kembali;} '
Fil
4

Berkat HTML5, Anda sekarang dapat mendeklarasikan skrip yang ingin Anda muat secara asinkron dengan menambahkan "asinkron" di tag:

<script async>...</script>

Catatan: Atribut async hanya untuk skrip eksternal (dan sebaiknya hanya digunakan jika atribut src ada).

Catatan: Ada beberapa cara untuk mengeksekusi skrip eksternal:

  • Jika asinkron ada: Skrip dijalankan secara tidak sinkron dengan sisa halaman (skrip akan dijalankan saat halaman melanjutkan penguraian)
  • Jika async tidak ada dan penundaan ada: Skrip dijalankan ketika halaman selesai parsing
  • Jika tidak ada async atau defer: Skrip diambil dan dijalankan segera, sebelum browser melanjutkan penguraian halaman

Lihat ini: http://www.w3schools.com/tags/att_script_async.asp

odroz.dll
sumber
2

Saya akan menyelesaikan jawaban zzzzBov dengan memeriksa keberadaan callback dan mengizinkan lewatnya argumen:

    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);
    }
Tibo
sumber
2

Berikut adalah solusi kontemporer yang bagus untuk pemuatan skrip asinkron meskipun hanya menangani skrip js dengan async false .

Ada artikel bagus yang ditulis di www.html5rocks.com - Selami perairan keruh pemuatan skrip .

Setelah mempertimbangkan banyak kemungkinan solusi, penulis menyimpulkan bahwa menambahkan skrip js ke akhir elemen badan adalah cara terbaik untuk menghindari pemblokiran perenderan halaman oleh skrip js.

Sementara itu, penulis menambahkan solusi alternatif lain yang bagus untuk orang-orang yang putus asa untuk memuat dan mengeksekusi skrip secara asinkron.

Mengingat Anda memiliki empat skrip bernama script1.js, script2.js, script3.js, script4.jsmaka Anda dapat melakukannya dengan menerapkan async = false :

[
  '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);
});

Sekarang, Spec mengatakan : Unduh bersama, jalankan secara berurutan segera setelah semua unduhan.

Firefox <3.6, Opera berkata: Saya tidak tahu apa itu "async", tapi kebetulan saya mengeksekusi skrip yang ditambahkan melalui JS sesuai urutan penambahannya.

Safari 5.0 mengatakan: Saya mengerti "async", tapi tidak mengerti menyetelnya ke "false" dengan JS. Saya akan menjalankan skrip Anda segera setelah mendarat, dalam urutan apa pun.

IE <10 mengatakan: Tidak tahu tentang "async", tetapi ada solusi untuk menggunakan "onreadystatechange".

Segala sesuatu yang lain mengatakan: Saya teman Anda, kami akan melakukan ini berdasarkan buku.

Sekarang, kode lengkap dengan IE <10 solusi:

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>');
  }
}
asmmahmud
sumber
1

Salah satu alasan mengapa skrip Anda dimuat dengan sangat lambat adalah jika Anda menjalankan semua skrip Anda saat memuat halaman, seperti ini:

callMyFunctions();

dari pada:

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

Bit kedua dari skrip ini menunggu sampai browser telah memuat semua kode Javascript Anda sebelum mulai menjalankan skrip Anda, membuatnya tampak bagi pengguna bahwa halaman telah dimuat lebih cepat.

Jika Anda ingin meningkatkan pengalaman pengguna dengan mengurangi waktu pemuatan, saya tidak akan memilih opsi "layar pemuatan". Menurut pendapat saya itu akan jauh lebih menjengkelkan daripada hanya memuat halaman lebih lambat.

didalamnya
sumber
1

Saya sarankan Anda melihat Modernizr . Ini adalah pustaka kecil yang ringan sehingga Anda dapat memuat javascript secara asinkron dengan fitur yang memungkinkan Anda memeriksa apakah file dimuat dan mengeksekusi skrip di tempat lain yang Anda tentukan.

Berikut contoh loading jquery:

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'
  }
]);
Shawn Mclean
sumber
1

Saya menulis sedikit posting untuk membantu hal ini, Anda dapat membaca lebih lanjut di sini https://timber.io/snippets/asynchronously-load-a-script-in-the-browser-with-javascript/ , tetapi saya telah melampirkan kelas helper di bawah ini. Ini secara otomatis akan menunggu skrip untuk memuat dan mengembalikan atribut jendela yang ditentukan setelah itu.

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

Penggunaannya seperti ini:

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()
Zach
sumber
1

Anda mungkin menemukan artikel wiki ini menarik: http://ajaxpatterns.org/On-Demand_Javascript

Ini menjelaskan bagaimana dan kapan menggunakan teknik tersebut.

tereško
sumber
Sayangnya, tautan tersebut tampaknya mati. :(
Eric Seastrand
@Eric itu karena itu adalah metode kuno untuk memuat kode secara dinamis: D
tereško
0

Nah, x.parentNodemengembalikan elemen HEAD, jadi Anda memasukkan skrip tepat sebelum tag head. Mungkin itu masalahnya.

Coba x.parentNode.appendChild()saja.

alekop
sumber
0

Lihat https://github.com/stephen-lazarionok/async-resource-loader ini . Ini memiliki contoh yang menunjukkan bagaimana memuat JS, CSS dan banyak file dengan satu tembakan.

Stephen L.
sumber
Dimungkinkan untuk mengubahnya sedikit untuk menghilangkan ketergantungan jquery
Stephen L.
0

Anda dapat menggunakan LABJS atau RequreJS

Pemuat skrip seperti LABJS, RequireJSakan meningkatkan kecepatan dan kualitas kode Anda.

Kaushik
sumber
0

Apakah Anda pernah mempertimbangkan untuk Fetch Injection? Saya meluncurkan pustaka sumber terbuka yang disebut fetch-inject untuk menangani kasus seperti ini. Beginilah tampilan loader Anda menggunakan lib:

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'
})

Untuk kompatibilitas mundur, deteksi fitur fitur dan kembali ke Injeksi XHR atau Elemen DOM Skrip, atau cukup sebariskan tag ke dalam halaman menggunakan document.write.

Josh Habdas
sumber
0

Berikut adalah solusi khusus saya untuk menghilangkan JavaScript yang memblokir perenderan:

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

Singkatnya, itu memuat semua skrip Anda secara asinkron, dan kemudian mengeksekusinya secara konsekuen.

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

Damjan Pavlica
sumber
1
Tidak bekerjaNo 'Access-Control-Allow-Origin' header is present on the requested resource
Abram
1
Itu adalah masalah CORS. stackoverflow.com/questions/20035101/…
Damjan Pavlica
0

Di sini sedikit fungsi ES6 jika seseorang ingin menggunakannya di React misalnya

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`)
  }
}

JoxieMedina
sumber
-3

Saya akan menyarankan untuk melihat ke dalam mengecilkan file terlebih dahulu dan melihat apakah itu memberi Anda peningkatan kecepatan yang cukup besar. Jika host Anda lambat, dapat mencoba meletakkan konten statis tersebut di CDN.

Jason Miesionczek
sumber