Cara memasukkan beberapa file js menggunakan metode jQuery $ .getScript ()


127

Saya mencoba untuk secara dinamis memasukkan file javascript ke file js saya. Saya melakukan riset tentang hal itu dan menemukan metode jQuery $ .getScript () akan menjadi cara yang diinginkan.

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // script is now loaded and executed.
    // put your dependent JS here.
    // what if the JS code is dependent on multiple JS files? 
});

Tetapi saya bertanya-tanya apakah metode ini dapat memuat banyak skrip sekaligus? Mengapa saya menanyakan hal ini adalah karena kadang-kadang file javascript saya tergantung pada lebih dari satu file js.

Terima kasih sebelumnya.

Jawaban:


315

Jawabannya adalah

Anda dapat menggunakan janji dengan getScript()dan menunggu hingga semua skrip dimuat, seperti:

$.when(
    $.getScript( "/mypath/myscript1.js" ),
    $.getScript( "/mypath/myscript2.js" ),
    $.getScript( "/mypath/myscript3.js" ),
    $.Deferred(function( deferred ){
        $( deferred.resolve );
    })
).done(function(){
    
    //place your code here, the scripts are all loaded
    
});

BIOLA

FIDDLE LAIN

Dalam kode di atas, menambahkan Tangguhan dan menyelesaikannya di dalam $()adalah seperti menempatkan fungsi lain di dalam panggilan jQuery, seperti $(func), itu sama dengan

$(function() { func(); });

yaitu menunggu DOM siap, jadi dalam contoh di atas $.whenmenunggu semua skrip untuk dimuat dan untuk DOM siap karena $.Deferredpanggilan yang diselesaikan dalam DOM ready callback.


Untuk penggunaan yang lebih umum, fungsi praktis

Fungsi utilitas yang menerima berbagai skrip dapat dibuat seperti ini:

$.getMultiScripts = function(arr, path) {
    var _arr = $.map(arr, function(scr) {
        return $.getScript( (path||"") + scr );
    });
        
    _arr.push($.Deferred(function( deferred ){
        $( deferred.resolve );
    }));
        
    return $.when.apply($, _arr);
}

yang bisa digunakan seperti ini

var script_arr = [
    'myscript1.js', 
    'myscript2.js', 
    'myscript3.js'
];

$.getMultiScripts(script_arr, '/mypath/').done(function() {
    // all scripts loaded
});

di mana path akan ditambahkan ke semua skrip, dan juga opsional, yang berarti bahwa jika array berisi URL lengkap, salah satunya juga bisa melakukan ini, dan biarkan path bersama-sama

$.getMultiScripts(script_arr).done(function() { ...

Argumen, kesalahan, dll.

Sebagai tambahan, perhatikan bahwa donepanggilan balik akan berisi sejumlah argumen yang cocok dengan skrip yang diteruskan, setiap argumen mewakili array yang berisi respons

$.getMultiScripts(script_arr).done(function(response1, response2, response3) { ...

di mana setiap array akan berisi sesuatu seperti [content_of_file_loaded, status, xhr_object]. Kita biasanya tidak perlu mengakses argumen itu karena skrip akan dimuat secara otomatis, dan sebagian besar waktu donepanggilan balik adalah kita benar-benar setelah mengetahui bahwa semua skrip telah dimuat, saya hanya menambahkannya untuk kelengkapan , dan untuk kejadian langka ketika teks aktual dari file yang dimuat perlu diakses, atau ketika seseorang membutuhkan akses ke setiap objek XHR atau sesuatu yang serupa.

Juga, jika ada skrip yang gagal dimuat, penangan yang gagal akan dipanggil, dan skrip berikutnya tidak akan dimuat

$.getMultiScripts(script_arr).done(function() {
     // all done
}).fail(function(error) {
     // one or more scripts failed to load
}).always(function() {
     // always called, both on success and error
});

11
Terima kasih atas jawaban Anda. Bisakah Anda jelaskan mengapa menambahkan di $.Deferred(function( deferred ){$( deferred.resolve );})sini?
sozhen

11
Objek yang ditangguhkan tidak benar-benar ada hubungannya dengan janji yang memungkinkan Anda memuat banyak skrip dan menjalankan fungsi saat semuanya selesai. Itu hanya memeriksa untuk melihat apakah $ () sudah siap, dan memutuskan jika itu, dengan kata lain memeriksa untuk melihat bahwa DOM siap sebelum mengeksekusi kode apa pun, seperti dokumen. Sudah, dan saya menemukan contoh yang baik melampirkan berjanji untuk getScript online yang memiliki fungsi siap DOM tangguhan dalam kode, dan hanya memutuskan untuk menyimpannya karena kedengarannya seperti ide yang bagus.
adeneo

4
Itu karena caching di ajax dimatikan secara default di jQuery, untuk mengaktifkannya dan menghapus querystring do: $.ajaxSetup({ cache: true });tetapi itu juga dapat memengaruhi panggilan ajax lain yang tidak ingin Anda cache, ada banyak lagi tentang ini di dokumen untuk getScript , dan bahkan ada sedikit howto tentang cara membuat fungsi getScript cached yang disebut cachedScript.
adeneo

3
Maaf atas keterlambatan penerimaan. Terkadang cara Anda masih kurang berhasil. Tidak yakin apa alasannya. Saya mencoba menggabungkan empat file skrip sekaligus. $.when($.getScript(scriptSrc_1), $.getScript(scriptSrc_2), $.getScript(scriptSrc_3), $.getScript(scriptSrc_4), $.Deferred(function(deferred) { $(deferred.resolve); })).done(function() { ... })
sozhen

1
Bagi siapa pun yang tidak bisa menjalankan ini, pastikan tidak ada kesalahan parse dalam file JS Anda yaitu pengujian bahwa mereka memuat dengan benar dalam tag <script> terlebih dahulu. jQuery.getScript () akan menganggap kesalahan ini sebagai gagal memuat dan .fail () akan dipanggil alih-alih .done (). @ LongtaoZ.
kekuatan prisma bulan

29

Saya menerapkan fungsi sederhana untuk memuat banyak skrip secara paralel:

Fungsi

function getScripts(scripts, callback) {
    var progress = 0;
    scripts.forEach(function(script) { 
        $.getScript(script, function () {
            if (++progress == scripts.length) callback();
        }); 
    });
}

Pemakaian

getScripts(["script1.js", "script2.js"], function () {
    // do something...
});

1
Untuk beberapa alasan, ini bekerja lebih baik daripada Emanuel. Ini juga implementasi yang sangat transparan.
Todd

@ satnam, terima kasih :)! jawaban teratas tidak berfungsi untuk beberapa orang (termasuk saya) jadi saya memposting solusi ini. Dan itu terlihat jauh lebih sederhana.
Andrei

10

Muat skrip yang diperlukan berikut dalam panggilan balik dari yang sebelumnya seperti:

$.getScript('scripta.js', function()
{
   $.getScript('scriptb.js', function()
   {
       // run script that depends on scripta.js and scriptb.js
   });
});

1
Tentunya metode ini akan mengunduh skrip secara berurutan, memperlambat waktu hingga eksekusi akhir?
Jimbo

1
Benar, @Jimbo - bersikap adil; itu lebih baik daripada eksekusi dini. :)
Alastair

Air terjun hampir selalu harus dihindari. getScript hadir dengan janji ... Anda dapat menggunakan $ .when untuk mendengarkan ketika janji terselesaikan.
Roi

@Roi dan orang lain: Jika saya perlu skrip untuk memuat dalam PESANAN KHUSUS, apa, pada dasarnya, apa yang salah dengan pendekatan ini? Dan, apa manfaatnya, yang dibawa oleh alternatif yang dijanjikan?
Ifedi Okonkwo

@IfediOkonkwo ini berfungsi ketika mereka harus dalam seri, tetapi awalnya hanya menyebutkan bahwa ia ingin kelipatan sekaligus (di mana, ini akan menjadi anti-pola). Meskipun begitu, jika saya menginginkannya secara seri, saya akan menulis fungsi looping yang bisa saya gunakan untuk array. Sarang yang dalam menjadi cepat berantakan.
Roi

9

Terkadang perlu memuat skrip dalam urutan tertentu. Misalnya jQuery harus dimuat sebelum jQuery UI. Sebagian besar contoh pada halaman ini memuat skrip secara paralel (asinkron) yang berarti urutan eksekusi tidak dijamin. Tanpa memesan, skrip yyang bergantung pada xdapat rusak jika keduanya berhasil dimuat tetapi dalam urutan yang salah.

Saya mengusulkan pendekatan hybrid yang memungkinkan pemuatan berurutan dari skrip dependen + pemuatan paralel opsional + objek yang ditangguhkan :

/*
 * loads scripts one-by-one using recursion
 * returns jQuery.Deferred
 */
function loadScripts(scripts) {
  var deferred = jQuery.Deferred();

  function loadScript(i) {
    if (i < scripts.length) {
      jQuery.ajax({
        url: scripts[i],
        dataType: "script",
        cache: true,
        success: function() {
          loadScript(i + 1);
        }
      });
    } else {
      deferred.resolve();
    }
  }
  loadScript(0);

  return deferred;
}

/*
 * example using serial and parallel download together
 */

// queue #1 - jquery ui and jquery ui i18n files
var d1 = loadScripts([
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js",
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/i18n/jquery-ui-i18n.min.js"
]).done(function() {
  jQuery("#datepicker1").datepicker(jQuery.datepicker.regional.fr);
});

// queue #2 - jquery cycle2 plugin and tile effect plugin
var d2 = loadScripts([
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/jquery.cycle2.min.js",
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/plugin/jquery.cycle2.tile.min.js"

]).done(function() {
  jQuery("#slideshow1").cycle({
    fx: "tileBlind",
    log: false
  });
});

// trigger a callback when all queues are complete
jQuery.when(d1, d2).done(function() {
  console.log("All scripts loaded");
});
@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/blitzer/jquery-ui.min.css");

#slideshow1 {
  position: relative;
  z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<p><input id="datepicker1"></p>

<div id="slideshow1">
  <img src="https://dummyimage.com/300x100/FC0/000">
  <img src="https://dummyimage.com/300x100/0CF/000">
  <img src="https://dummyimage.com/300x100/CF0/000">
</div>

Skrip di kedua antrian akan mengunduh secara paralel, namun skrip di setiap antrian akan mengunduh secara berurutan, memastikan eksekusi yang dipesan. Grafik air terjun:

bagan skrip air terjun


Tidakkah kita perlu menambahkan tag skrip dalam HTML setelah skrip dimuat dalam memori?
Ankush Jain

4

Gunakan yepnope.js atau Modernizr (yang mencakup yepnope.js sebagai Modernizr.load).

MEMPERBARUI

Hanya untuk menindaklanjuti, berikut ini setara dengan apa yang Anda miliki saat ini menggunakan yepnope, yang menunjukkan dependensi pada banyak skrip:

yepnope({
  load: ['script1.js', 'script2.js', 'script3.js'],
  complete: function () {
      // all the scripts have loaded, do whatever you want here
  }
});

Terima kasih. Dapatkah saya menggunakan beberapa yepnope.injectJs( scriptSource )di awal file javascript saya seperti memasukkan <script>tag dalam file html?
sozhen

Itu baru, dan jujur, saya tidak mengerti mengapa itu diperlukan. Ikuti dokumentasi turun sedikit melewati daftar perubahan terbaru dan Anda akan melihat penggunaan yang lebih konvensional.
Chris Pratt

+1; perlu dicatat bahwa ini benar mengelola dependensi (yaitu tidak akan memuat skrip yang sama dua kali) tidak seperti $.getScript. Ini masalah besar.
Ov

yepnope.js sekarang sudah tidak digunakan lagi .
Stephan

4

Saya mengalami sejumlah masalah dengan pemuatan multi skrip yang memasukkan satu masalah dengan (setidaknya di Chrome) domain hot loading yang sama dari skrip yang tidak benar-benar berjalan setelah berhasil dimuat oleh Ajax di mana Cross Domain berfungsi dengan sangat baik! :(

Jawaban yang dipilih untuk pertanyaan awal tidak berfungsi dengan baik.

Setelah banyak banyak iterasi di sini adalah jawaban terakhir saya untuk getScript (s) dan memuat beberapa skrip asinkron dalam urutan ketat tertentu dengan opsi pemanggilan kembali panggilan per skrip dan pemanggilan kembali secara keseluruhan saat penyelesaian, Diuji dalam jQuery 2.1+ dan versi modern Chrome, Firefox plus the meninggalkan Internet Explorer.

Kasus pengujian saya memuat file untuk render THREE.JS webGL kemudian memulai skrip render ketika THREE global tersedia menggunakan pemeriksaan interval yang diteruskan ke panggilan fungsi anonim ke onComplete.

Fungsi Prototipe (getScripts)

function getScripts( scripts, onScript, onComplete )
{
    this.async = true;
    this.cache = false;
    this.data = null;
    this.complete = function () { $.scriptHandler.loaded(); };
    this.scripts = scripts;
    this.onScript = onScript;
    this.onComplete = onComplete;
    this.total = scripts.length;
    this.progress = 0;
};

getScripts.prototype.fetch = function() {
    $.scriptHandler = this;
    var src = this.scripts[ this.progress ];
    console.log('%cFetching %s','color:#ffbc2e;', src);

    $.ajax({
        crossDomain:true,
        async:this.async,
        cache:this.cache,
        type:'GET',
        url: src,
        data:this.data,
        statusCode: {
            200: this.complete
        },
        dataType:'script'
    });
};

getScripts.prototype.loaded = function () {
    this.progress++;
    if( this.progress >= this.total ) {
        if(this.onComplete) this.onComplete();
    } else {
        this.fetch();
    };
    if(this.onScript) this.onScript();
};

Cara Penggunaan

var scripts = new getScripts(
    ['script1.js','script2.js','script.js'],
    function() {
        /* Optional - Executed each time a script has loaded (Use for Progress updates?) */
    },
    function () {
        /* Optional - Executed when the entire list of scripts has been loaded */
    }
);
scripts.fetch();

Fungsi ini seperti untuk yang saya temukan menggunakan Ditangguhkan (Tidak digunakan sekarang?), Kapan, Sukses & Lengkap dalam uji coba saya untuk TIDAK 100% dapat diandalkan!?, Oleh karena itu fungsi ini dan penggunaan statusCode misalnya.

Anda mungkin ingin menambahkan perilaku penanganan kesalahan / gagal jika diinginkan.


+1 untuk memuatnya dalam urutan yang benar, sering kali penting, dan sesuatu jawaban yang diterima tidak akan menjamin kecuali saya melewatkan sesuatu? Saya telah memposting jawaban pendek yang serupa di bawah ini tetapi ini adalah kasus yang lebih umum
Whelkaholism

2

Anda bisa menggunakan $.when-method dengan mencoba fungsi berikut:

function loadScripts(scripts) {
  scripts.forEach(function (item, i) {
    item = $.getScript(item);
  });
  return $.when.apply($, scripts);
}

Fungsi ini akan digunakan seperti ini:

loadScripts(['path/to/script-a.js', 'path/to/script-b.js']).done(function (respA, respB) {
    // both scripts are loaded; do something funny
});

Itulah cara menggunakan Janji dan memiliki biaya overhead minimum.


Apakah ini memastikan skrip dimuat secara berurutan?
CyberMonk

2

Jawaban yang bagus, adeneo.

Butuh beberapa saat untuk mencari tahu bagaimana membuat jawaban Anda lebih umum (sehingga saya bisa memuat array skrip yang ditentukan kode). Callback dipanggil ketika semua skrip telah dimuat dan dieksekusi. Ini solusinya:

    function loadMultipleScripts(scripts, callback){
        var array = [];

        scripts.forEach(function(script){
            array.push($.getScript( script ))
        });

        array.push($.Deferred(function( deferred ){
                    $( deferred.resolve );
                }));

        $.when.apply($, array).done(function(){
                if (callback){
                    callback();
                }
            });
    }

2

Tambahkan skrip dengan async = false

Inilah pendekatan yang berbeda, tetapi super sederhana. Untuk memuat banyak skrip, Anda cukup menambahkannya ke badan.

  • Memuatnya secara tidak sinkron, karena itulah cara browser mengoptimalkan pemuatan halaman
  • Menjalankan skrip secara berurutan, karena itulah cara browser mengurai tag HTML
  • Tidak perlu untuk dipanggil kembali, karena skrip dijalankan secara berurutan. Cukup tambahkan skrip lain, dan itu akan dieksekusi setelah skrip lainnya

Info lebih lanjut di sini: https://www.html5rocks.com/en/tutorials/speed/script-loading/

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

1

Apa yang Anda cari adalah loader AMD yang kompatibel (seperti require.js).

http://requirejs.org/

http://requirejs.org/docs/whyamd.html

Ada banyak sumber terbuka yang bagus jika Anda mencarinya. Pada dasarnya ini memungkinkan Anda untuk mendefinisikan modul kode, dan jika tergantung pada modul kode lainnya, ia akan menunggu sampai modul-modul tersebut selesai diunduh sebelum melanjutkan untuk menjalankan. Dengan cara ini Anda dapat memuat 10 modul secara tidak sinkron dan seharusnya tidak ada masalah walaupun satu tergantung pada beberapa modul lainnya untuk dijalankan.


1

Fungsi ini akan memastikan bahwa file dimuat setelah file dependensi dimuat sepenuhnya. Anda hanya perlu memberikan file secara berurutan dengan mengingat dependensi pada file lain.

function loadFiles(files, fn) {
    if (!files.length) {
        files = [];
    }
    var head = document.head || document.getElementsByTagName('head')[0];

    function loadFile(index) {
        if (files.length > index) {
            var fileref = document.createElement('script');
            fileref.setAttribute("type", "text/javascript");
            fileref.setAttribute("src", files[index]);
            head.appendChild(fileref);
            index = index + 1;
            // Used to call a callback function
            fileref.onload = function () {
                loadFile(index);
            }
        } else if(fn){
            fn();
        }
    }
    loadFile(0);
}

Mungkin lebih baik daripada jawaban yang diterima karena memuat file secara berurutan. Jika script2 membutuhkan script1 untuk dimuat maka pemesanan sangat penting.
Salman A

1

Ini bekerja untuk saya:

function getScripts(scripts) {
    var prArr = [];
    scripts.forEach(function(script) { 
        (function(script){
            prArr .push(new Promise(function(resolve){
                $.getScript(script, function () {
                    resolve();
                });
            }));
        })(script);
    });
    return Promise.all(prArr, function(){
        return true;
    });
}

Dan gunakan itu:

var jsarr = ['script1.js','script2.js'];
getScripts(jsarr).then(function(){
...
});

1

Berikut ini jawaban menggunakan pertanyaan Maciej Sawicki dan menerapkannya Promisesebagai panggilan balik:

function loadScripts(urls, path) {
    return new Promise(function(resolve) {
        urls.forEach(function(src, i) {

            let script = document.createElement('script');        
            script.type = 'text/javascript';
            script.src = (path || "") + src;
            script.async = false;

            // If last script, bind the callback event to resolve
            if(i == urls.length-1) {                    
                // Multiple binding for browser compatibility
                script.onreadystatechange = resolve;
                script.onload = resolve;
            }

            // Fire the loading
            document.body.appendChild(script);
        });
    });
}

Menggunakan:

let JSDependencies = ["jquery.js",
                      "LibraryNeedingJquery.js",
                      "ParametersNeedingLibrary.js"];

loadScripts(JSDependencies,'JavaScript/').then(taskNeedingParameters);

Semua file Javascript diunduh secepat mungkin dan dieksekusi dalam urutan yang diberikan. Kemudian taskNeedingParametersdipanggil.


0

Versi singkat dari jawaban komprehensif Andrew Marc Newton di atas. Yang ini tidak memeriksa kode status untuk berhasil, yang harus Anda lakukan untuk menghindari perilaku UI yang tidak ditentukan.

Yang satu ini untuk sistem yang menjengkelkan di mana saya bisa menjamin jQuery tetapi tidak termasuk yang lain, jadi saya ingin teknik yang cukup singkat untuk tidak digali menjadi skrip eksternal jika dipaksa ke dalamnya. (Anda bisa membuatnya lebih pendek dengan melewati indeks 0 ke panggilan "rekursif" pertama tetapi gaya kebiasaan membuat saya menambahkan gula).

Saya juga menetapkan daftar dependensi ke nama modul, jadi blok ini dapat dimasukkan di mana saja Anda memerlukan "module1" dan skrip dan inisialisasi dependen hanya akan disertakan / dijalankan sekali (Anda dapat login indexke callback dan melihat satu pun yang dipesan set permintaan runnning AJAX)

if(typeof(__loaders) == 'undefined') __loaders = {};

if(typeof(__loaders.module1) == 'undefined')
{
    __loaders.module1 = false;

    var dependencies = [];

    dependencies.push('/scripts/loadmefirst.js');
    dependencies.push('/scripts/loadmenext.js');
    dependencies.push('/scripts/loadmelast.js');

    var getScriptChain  = function(chain, index)        
    {
        if(typeof(index) == 'undefined')
            index = 0;

        $.getScript(chain[index], 
            function()
            {
                if(index == chain.length - 1)
                {
                    __loaders.module1 = true;

                    /* !!!
                        Do your initialization of dependent stuff here 
                    !!! */
                }
                else 
                    getScriptChain(chain, index + 1);
            }
        );
    };

    getScriptChain(dependencies);       
}


0

Memuat n skrip satu per satu (berguna jika misalnya file ke-2 membutuhkan yang pertama):

(function self(a,cb,i){
    i = i || 0; 
    cb = cb || function(){};    
    if(i==a.length)return cb();
    $.getScript(a[i++],self.bind(0,a,cb,i));                    
})(['list','of','script','urls'],function(){console.log('done')});

0

berdasarkan jawaban dari @adeneo di atas: Menggabungkan pemuatan file css dan js

ada saran untuk perbaikan ??

// Usage
//$.getMultiResources(['script-1.js','style-1.css'], 'assets/somePath/')
//  .done(function () {})
//  .fail(function (error) {})
//  .always(function () {});

(function ($) {
  $.getMultiResources = function (arr, pathOptional, cache) {
    cache = (typeof cache === 'undefined') ? true : cache;
    var _arr = $.map(arr, function (src) {
      var srcpath = (pathOptional || '') + src;
      if (/.css$/i.test(srcpath)) {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'text',
          cache: cache,
          success: function () {
            $('<link>', {
              rel: 'stylesheet',
              type: 'text/css',
              'href': srcpath
            }).appendTo('head');
          }
        });

      } else {
        return $.ajax({
          type: 'GET',
          url: srcpath,
          dataType: 'script',
          cache: cache
        });
      }
    });
    //
    _arr.push($.Deferred(function (deferred) {
      $(deferred.resolve);
    }));
    //
    return $.when.apply($, _arr);
  };
})(jQuery);

0

Anda dapat mencoba ini menggunakan rekursi. Ini akan mengunduhnya dalam sinkronisasi, satu demi satu hingga selesai mengunduh seluruh daftar.

var queue = ['url/links/go/here'];

ProcessScripts(function() { // All done do what ever you want

}, 0);

function ProcessScripts(cb, index) {
    getScript(queue[index], function() {
        index++;
        if (index === queue.length) { // Reached the end
            cb();
        } else {
            return ProcessScripts(cb, index);
        }
    });
}

function getScript(script, callback) {
    $.getScript(script, function() {
        callback();
    });
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.