Bagaimana cara saya memasukkan file JavaScript ke file JavaScript lain?

5194

Apakah ada sesuatu dalam JavaScript yang mirip dengan @importdi CSS yang memungkinkan Anda untuk memasukkan file JavaScript ke dalam file JavaScript lain?

Alec Smart
sumber
82
@Aniel, saya tidak ingin menggunakan panggilan AJAX.
Alec Smart
13
Mengapa tidak mendeklarasikan file yang diimpor sebelum yang lain yang membutuhkannya, hanya menggunakan scripttag yang dipesan ?
falsarella
6
@Claudiu Itu tidak akan membantu untuk mengimpor apa pun, tetapi itu harus bekerja juga. Jika Anda memiliki file JS yang bergantung pada file JS lainnya, cukup deklarasikan tag skrip dari file dependensi terlebih dahulu, sehingga nanti dependensinya sudah dimuat. Jika Anda memiliki situasi di mana itu bukan pendekatan yang mungkin, jawaban di sini harus membantu.
falsarella
1
apa keuntungan praktis dari melakukan ini? baik cara basis kode tergantung pada file javascript tidak akan memuat dan mulai bekerja dalam hal apapun itu tidak dimuat!
Ciasto piekarz

Jawaban:

4472

Versi lama JavaScript tidak mengimpor, memasukkan, atau mengharuskan, begitu banyak pendekatan berbeda untuk masalah ini telah dikembangkan.

Tetapi sejak 2015 (ES6), JavaScript telah memiliki standar modul ES6 untuk mengimpor modul di Node.js, yang juga didukung oleh sebagian besar peramban modern .

Untuk kompatibilitas dengan browser yang lebih lama, alat build seperti Webpack dan Rollup dan / atau alat transpilasi seperti Babel dapat digunakan.

Modul ES6

Modul ECMAScript (ES6) telah didukung di Node.js sejak v8.5, dengan --experimental-modulesflag, dan setidaknya Node.js v13.8.0 tanpa flag. Untuk mengaktifkan "ESM" (vs. sistem modul CommonJS-gaya sebelumnya Node.js ini [ "CJS"]) Anda baik menggunakan "type": "module"di package.jsonatau memberikan file ekstensi .mjs. (Demikian pula, modul yang ditulis dengan modul CJS Node.js sebelumnya dapat dinamai .cjsjika default Anda adalah ESM.)

Menggunakan package.json:

{
    "type": "module"
}

Lalu module.js:

export function hello() {
  return "Hello";
}

Lalu main.js:

import { hello } from './module.js';
let val = hello();  // val is "Hello";

Dengan menggunakan .mjs, Anda harus module.mjs:

export function hello() {
  return "Hello";
}

Lalu main.mjs:

import { hello } from './module.mjs';
let val = hello();  // val is "Hello";

Modul ECMAScript di browser

Browser telah mendapat dukungan untuk memuat modul ECMAScript secara langsung (tidak diperlukan alat seperti Webpack) sejak Safari 10.1, Chrome 61, Firefox 60, dan Edge 16. Periksa dukungan saat ini di caniuse . Tidak perlu menggunakan .mjsekstensi Node.js ; browser sepenuhnya mengabaikan ekstensi file pada modul / skrip.

<script type="module">
  import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
  hello('world');
</script>
// hello.mjs -- or it could be simply `hello.js`
export function hello(text) {
  const div = document.createElement('div');
  div.textContent = `Hello ${text}`;
  document.body.appendChild(div);
}

Baca lebih lanjut di https://jakearchibald.com/2017/es-modules-in-browsers/

Impor dinamis di browser

Impor dinamis membiarkan skrip memuat skrip lain sesuai kebutuhan:

<script type="module">
  import('hello.mjs').then(module => {
      module.hello('world');
    });
</script>

Baca lebih lanjut di https://developers.google.com/web/updates/2017/11/dynamic-import

Node.js membutuhkan

Gaya modul CJS yang lebih lama, masih banyak digunakan di Node.js, adalah module.exports/require sistem.

// mymodule.js
module.exports = {
   hello: function() {
      return "Hello";
   }
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"   

Ada cara lain untuk JavaScript untuk memasukkan konten JavaScript eksternal di browser yang tidak memerlukan preprocessing.

Memuat AJAX

Anda dapat memuat skrip tambahan dengan panggilan AJAX dan kemudian gunakan evaluntuk menjalankannya. Ini adalah cara yang paling mudah, tetapi terbatas pada domain Anda karena model keamanan JavaScript sandbox. Menggunakan evaljuga membuka pintu bagi bug, peretasan, dan masalah keamanan.

Ambil Memuat

Seperti Impor dinamis, Anda dapat memuat satu atau banyak skrip dengan fetchpanggilan menggunakan janji untuk mengontrol urutan eksekusi untuk dependensi skrip menggunakan pustaka Inject Ambil :

fetchInject([
  'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
  console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})

jQuery Sedang Memuat

The jQuery perpustakaan menyediakan memuat fungsi dalam satu baris :

$.getScript("my_lovely_script.js", function() {
   alert("Script loaded but not necessarily executed.");
});

Memuat Script Dinamis

Anda dapat menambahkan tag skrip dengan URL skrip ke dalam HTML. Untuk menghindari overhead jQuery, ini adalah solusi ideal.

Skrip bahkan dapat berada di server yang berbeda. Selanjutnya, browser mengevaluasi kode. The <script>tag dapat disuntikkan ke dalam salah satu halaman web <head>, atau dimasukkan sebelum penutupan </body>tag.

Berikut adalah contoh bagaimana ini bisa bekerja:

function dynamicallyLoadScript(url) {
    var script = document.createElement("script");  // create a script DOM node
    script.src = url;  // set its src to the provided URL

    document.head.appendChild(script);  // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}

Fungsi ini akan menambahkan <script>tag baru ke akhir bagian kepala halaman, di mana srcatribut diatur ke URL yang diberikan ke fungsi sebagai parameter pertama.

Kedua solusi ini dibahas dan diilustrasikan dalam JavaScript Madness: Dynamic Script Loading .

Mendeteksi ketika skrip telah dieksekusi

Sekarang, ada masalah besar yang harus Anda ketahui. Melakukan hal itu menyiratkan bahwa Anda memuat kode dari jarak jauh . Browser web modern akan memuat file dan terus mengeksekusi skrip Anda saat ini karena mereka memuat semuanya secara tidak sinkron untuk meningkatkan kinerja. (Ini berlaku untuk metode jQuery dan metode pemuatan skrip dinamis manual.)

Ini berarti bahwa jika Anda menggunakan trik ini secara langsung, Anda tidak akan dapat menggunakan kode yang baru dimuat di baris berikutnya setelah Anda memintanya untuk dimuat , karena masih akan memuat.

Misalnya: my_lovely_script.jsberisi MySuperObject:

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

Kemudian Anda memuat kembali halaman yang sedang dipukul F5. Dan itu berhasil! Membingungkan ...

Jadi apa yang harus dilakukan?

Nah, Anda dapat menggunakan retasan yang disarankan penulis di tautan yang saya berikan kepada Anda. Singkatnya, untuk orang-orang yang terburu-buru, ia menggunakan acara untuk menjalankan fungsi panggilan balik ketika skrip dimuat. Jadi Anda bisa meletakkan semua kode menggunakan pustaka jarak jauh di fungsi panggilan balik. Sebagai contoh:

function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.head;
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}

Kemudian Anda menulis kode yang ingin Anda gunakan SETELAH skrip dimuat dalam fungsi lambda :

var myPrettyCode = function() {
   // Here, do whatever you want
};

Kemudian Anda jalankan semua itu:

loadScript("my_lovely_script.js", myPrettyCode);

Perhatikan bahwa skrip dapat dijalankan setelah DOM dimuat, atau sebelumnya, tergantung pada browser dan apakah Anda menyertakan baris script.async = false;. Ada artikel hebat tentang pemuatan Javascript secara umum yang membahas hal ini.

Source Code Merge / Preprocessing

Seperti yang disebutkan di bagian atas jawaban ini, banyak pengembang menggunakan alat build / transpilation (s) seperti Parcel, Webpack, atau Babel dalam proyek mereka, memungkinkan mereka untuk menggunakan sintaks JavaScript yang akan datang, memberikan kompatibilitas ke belakang untuk browser lama, menggabungkan file, memperkecil, melakukan pemecahan kode dll.

e-satis
sumber
130
Tidak, tetapi seseorang yang menggunakan sesuatu yang semaju Badak atau yang lain tidak akan mengajukan pertanyaan ini.
e-satis
192
Untuk melengkapi, ada cara ketiga: Dalam solusi tertentu ketika Anda mengontrol kedua file javascript, Anda hanya dapat membuat 1 file javascript raksasa yang menggabungkan konten dari kedua file.
Kodok
20
Tidak boleh "mendokumentasikan.createElement (" my_lovely_script.js ");" dalam contoh menjadi "document.createElement (" script ")"?
Russell Silva
14
Bagaimana eval membuka pintu untuk meretas jika kode Anda yang Anda jalankan?
Vince Panuccio
6
Jawaban Anda memerlukan beberapa modifikasi untuk IE ( onreadystatechangeacara dan readyStateproperti). Juga, pemuatan skrip dinamis tidak mendapat manfaat dari pemindai preload dari broswer. Rekomendasikan artikel HTML5Rocks ini: html5rocks.com/en/tutorials/speed/script-loading
ruhong
570

Jika ada yang mencari sesuatu yang lebih maju, cobalah RequireJS . Anda akan mendapatkan manfaat tambahan seperti manajemen dependensi, konkurensi yang lebih baik, dan menghindari duplikasi (yaitu, mengambil skrip lebih dari sekali).

Anda dapat menulis file JavaScript di "modul" dan kemudian merujuknya sebagai dependensi di skrip lain. Atau Anda dapat menggunakan RequireJS sebagai solusi "go get this script" sederhana.

Contoh:

Tentukan dependensi sebagai modul:

some-dependency.js

define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {

     //Your actual script goes here.   
     //The dependent scripts will be fetched if necessary.

     return libraryObject;  //For example, jQuery object
});

implementasi.js adalah file JavaScript "utama" Anda yang bergantung pada some-dependency.js

require(['some-dependency'], function(dependency) {

    //Your script goes here
    //some-dependency.js is fetched.   
    //Then your script is executed
});

Kutipan dari GitHub README:

Mengharuskan JS memuat file JavaScript biasa serta modul yang lebih jelas. Ini dioptimalkan untuk penggunaan dalam browser, termasuk di Web Worker, tetapi dapat digunakan di lingkungan JavaScript lainnya, seperti Badak dan Node. Ini mengimplementasikan API Modul Asynchronous.

RequireJS menggunakan tag skrip biasa untuk memuat modul / file, sehingga harus memungkinkan untuk debugging mudah. Ini dapat digunakan hanya untuk memuat file JavaScript yang ada, sehingga Anda dapat menambahkannya ke proyek yang ada tanpa harus menulis ulang file JavaScript Anda.

...

John Strickler
sumber
1
@aaaidan: Alasan MattDmo ditambah lagi bergantung pada perpustakaan eksternal yang bergantung pada jawaban yang diterima.
David Mulder
1
Untuk mengatasi require.js yang terbaru adalah angular js yang lebih stabil dan mudah digunakan bersama dengan fitur HTML lainnya yang mengikat dan kaya.
zeeshan
5
-1: Abstraksi tersebut - "some_dependency" - benar-benar buruk, dengan indeks menambah kebingungan. Saya kesulitan memahami seperti apa contoh kode kerja. Jika penulis memberikan contoh kerja, hampir semua orang akan dapat menyesuaikan dan menggeneralisasikannya untuk kebutuhannya.
Tegiri Nenashi
1
tidak bekerja dengan baik dengan MVC dan bundling skrip dengan minifikasi otomatis
Triynko
1
'add .. w / o harus menulis ulang file JavaScript Anda'; keren, tapi bagaimana tepatnya? Bajingan. jawaban menyarankan menambahkan 'membutuhkan' (bukan 'diperlukan'?) ke skrip utama + 'menentukan' untuk setiap file dependen, ya? Tapi itu IS menulis ulang jadi apa yang tidak ditulis ulang? -tutup kode sejak RequireJS memungkinkan file ea membuat def global seperti biasa? -melakukannya? Saya baru saja mencobanya, + (lupa?) <Script src = " requiredejs.org/docs/release/2.2.0/comments/require.js "> </script>, lalu 'requireejs ([' GoogleDrive.com/host /..',..[,function(a, b) {mycode}) ': Firebug mengatakan setiap dependen dimuat TETAPI def mereka tidak didefinisikan dalam mycode & after.
Destiny Architect
195

Sebenarnya ada cara untuk memuat file JavaScript tidak asinkron, sehingga Anda dapat menggunakan fungsi yang disertakan dalam file yang baru Anda muat setelah memuatnya, dan saya pikir itu berfungsi di semua browser.

Anda perlu menggunakan jQuery.append()pada <head>elemen halaman Anda, yaitu:

$("head").append('<script type="text/javascript" src="' + script + '"></script>');

Namun, metode ini juga memiliki masalah: jika terjadi kesalahan pada file JavaScript yang diimpor, Firebug (dan juga Firefox Error Console dan Tools Developer Chrome ) akan melaporkan tempatnya secara tidak benar, yang merupakan masalah besar jika Anda menggunakan Firebug untuk melacak Kesalahan JavaScript turun banyak (saya lakukan). Firebug tidak tahu tentang file yang baru dimuat karena suatu alasan, jadi jika terjadi kesalahan pada file itu, ia melaporkan bahwa itu terjadi pada file HTML utama Anda , dan Anda akan kesulitan menemukan alasan sebenarnya untuk kesalahan tersebut.

Tetapi jika itu bukan masalah bagi Anda, maka metode ini akan berhasil.

Saya sebenarnya telah menulis plugin jQuery yang disebut $ .import_js () yang menggunakan metode ini:

(function($)
{
    /*
     * $.import_js() helper (for JavaScript importing within JavaScript code).
     */
    var import_js_imported = [];

    $.extend(true,
    {
        import_js : function(script)
        {
            var found = false;
            for (var i = 0; i < import_js_imported.length; i++)
                if (import_js_imported[i] == script) {
                    found = true;
                    break;
                }

            if (found == false) {
                $("head").append('<script type="text/javascript" src="' + script + '"></script>');
                import_js_imported.push(script);
            }
        }
    });

})(jQuery);

Jadi yang perlu Anda lakukan untuk mengimpor JavaScript adalah:

$.import_js('/path_to_project/scripts/somefunctions.js');

Saya juga membuat tes sederhana untuk ini di Contoh .

Ini termasuk main.jsfile dalam HTML utama dan kemudian skrip main.jsdigunakan $.import_js()untuk mengimpor file tambahan yang disebut included.js, yang mendefinisikan fungsi ini:

function hello()
{
    alert("Hello world!");
}

Dan tepat setelah termasuk included.js, hello()fungsinya dipanggil, dan Anda mendapatkan peringatan.

(Jawaban ini sebagai respons terhadap komentar e-satis ').

Kipras
sumber
Saya mencoba metode ini, tetapi tidak berfungsi untuk saya, elemennya tidak muncul di tag kepala.
situs
16
@ juanpastas - gunakan jQuery.getScript, dengan begitu Anda tidak perlu khawatir menulis plugin ...
MattDMo
6
Hmm, menurut artikel ini , menambahkan scriptelemen headakan menyebabkannya berjalan secara tidak sinkron, kecuali jika asyncdiatur secara khusus false.
Flimm
1
Bukankah seharusnya variabel skrip memiliki entitas html dikodekan? Jika tautan berisi ", kode akan rusak
RedClover
1
@ Demi Tuhan, saya dan tim saya, terima kasih atas komentar Anda dan saya pribadi berhutang bir padamu seandainya kami bertemu langsung
Alex
155

Cara lain, yang menurut saya jauh lebih bersih, adalah dengan membuat permintaan Ajax sinkron daripada menggunakan <script>tag. Yang juga bagaimana Node.js menangani termasuk.

Berikut ini contoh menggunakan jQuery:

function require(script) {
    $.ajax({
        url: script,
        dataType: "script",
        async: false,           // <-- This is the key
        success: function () {
            // all good...
        },
        error: function () {
            throw new Error("Could not load script " + script);
        }
    });
}

Anda kemudian dapat menggunakannya dalam kode Anda karena biasanya Anda akan menggunakan sertakan:

require("/scripts/subscript.js");

Dan dapat memanggil fungsi dari skrip yang diperlukan di baris berikutnya:

subscript.doSomethingCool(); 
Ariel
sumber
1
Solusi bagus, kepala termasuk async sayangnya, solusi ajax bekerja.
Matteo Conta
17
Seperti orang lain yang disebutkan, requireejs.org melakukan ini dan juga memiliki pra-kompiler yang menyatukan file js sehingga mereka memuat lebih cepat. mungkin kamu ingin memeriksanya.
Ariel
2
Ditemukan saya bisa melakukan debug dengan menambahkan arahan ini di bagian bawah file untuk Chrome: // @ sourceURL = view_index.js
Todd Vance
11
Sayangnya, async: false sekarang tidak digunakan lagi di jQuery. Mungkin istirahat di masa depan, jadi saya akan menghindari.
sqram
3
@katsh Kami tidak menggunakan objek jqXHR di sini. Kutipan Anda tampaknya tidak mendukung komentar Anda sebelumnya yang menyatakan bahwa async: falsesudah usang. Bukan itu! Seperti kutipan Anda nyatakan, hanya hal-hal terkait jqXHR yang.
Zero3
101

Ada kabar baik untuk Anda. Segera Anda akan dapat memuat kode JavaScript dengan mudah. Ini akan menjadi cara standar untuk mengimpor modul kode JavaScript dan akan menjadi bagian dari inti JavaScript itu sendiri.

Anda hanya perlu menulis import cond from 'cond.js';untuk memuat nama makro conddari file cond.js.

Jadi Anda tidak harus bergantung pada kerangka JavaScript apa pun juga tidak harus secara eksplisit membuat panggilan Ajax .

Mengacu pada:

Imdad
sumber
12
memerlukan / impor di jsfile sudah terlalu lama di masa mendatang. (IMO).
rwheadon
6
@ rwheadon ya nampaknya mengerikan bahwa ini bukan bagian dari bahasa! Bagaimana orang-orang menyelesaikan sesuatu adalah di luar jangkauan saya! Saya baru
mengenalnya
@ jonny-leeds Bahkan tanpa pemuatan modul bawaan, JavaScript di browser cukup fleksibel sehingga kita dapat mengimplementasikan perpustakaan seperti RequireJS untuk manajemen modul kita.
Tertarik
8
pertengahan 2015- Masih belum diterapkan di peramban apa pun, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
scape
ya kamu benar sekarang saya mulai merasa tidak enak untuk ini :(. Engkau, setelah diterapkan di semua browser, ini akan menjadi fitur hebat untuk javascript.
Imdad
97

Dimungkinkan untuk secara dinamis menghasilkan tag JavaScript dan menambahkannya ke dokumen HTML dari dalam kode JavaScript lainnya. Ini akan memuat file JavaScript yang ditargetkan.

function includeJs(jsFilePath) {
    var js = document.createElement("script");

    js.type = "text/javascript";
    js.src = jsFilePath;

    document.body.appendChild(js);
}

includeJs("/path/to/some/file.js");
Svitlana Maksymchuk
sumber
8
@ e-satis - Sebenarnya, ini merupakan keuntungan, skrip sinkronisasi akan diblokir. Kuda untuk kursus, tetapi 9 kali dalam 10 Anda ingin opsi non-blocking.
annakata
@Svitlana - elemen skrip yang dibuat seperti ini adalah async. Saat ini ini dapat dilihat sebagai mengeksploitasi celah sehingga mungkin tidak menjadi bukti di masa depan, saya belum melihat apapun dalam standar apa pun yang menjelaskan hal ini.
annakata
Sebenarnya saya ambil kembali, saya perhatikan Anda menambahkan ke tubuh daripada kepala.
annakata
@annakata: Apa bedanya? BTW, yahoo menyarankan untuk menambahkan tag skrip ke ujung tubuh, jadi tidak ada yang salah dengan itu ketika menambahkan secara dinamis.
Svitlana Maksymchuk
7
@ e-satis asynchronous bagus karena tidak akan membekukan halaman Anda. Gunakan panggilan balik untuk diberitahukan ketika sudah selesaijs.onload = callback;
Vitim.us
74

Pernyataan importada dalam ECMAScript 6.

Sintaksis

import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name" as name;
Draupnie
sumber
... tetapi tidak didukung oleh browser apa pun hingga saat ini, sesuai dengan tabel kompatibilitas pada halaman yang Anda tautkan.
Zero3
6
Anda sekarang dapat menulis kode ES6 dan mengompilasinya dengan Babel.js ( babeljs.io ) untuk apa pun sistem modul yang Anda sukai saat ini (CommonJS / AMD / UMD): babeljs.io/docs/usage/modules
Jeremy Harris
@ Zero3 Rupanya hanya IE (Edge) yang baru
Julian Avar
pada tahun 2019 IE masih tidak mendukung ini dalam bentuk apa pun. Mengapa microsoft harus menentang penggunaan?
GreySage
61

Mungkin Anda dapat menggunakan fungsi ini yang saya temukan di halaman ini. Bagaimana cara saya memasukkan file JavaScript ke file JavaScript? :

function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';

    head.appendChild(script)
}
Arnaud Gouder de Beauregard
sumber
5
Seharusnya berguna untuk menambahkanscript.onload = callback;
Vitim.us
@SvitlanaMaksymchuk jadi, jika saya tidak menggunakan var, variabel akan bersifat global?
Francisco Corrales Morales
@ FranciscoCorrales ya.
Christopher Chiche
Itu berakhir di global dengan atau tanpa var :)
Vedran Maricevic.
54

Ini adalah versi sinkron tanpa jQuery :

function myRequire( url ) {
    var ajax = new XMLHttpRequest();
    ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous
    ajax.onreadystatechange = function () {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4) {
            switch( ajax.status) {
                case 200:
                    eval.apply( window, [script] );
                    console.log("script loaded: ", url);
                    break;
                default:
                    console.log("ERROR: script not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

Perhatikan bahwa untuk mendapatkan lintas-domain yang berfungsi ini, server perlu mengatur allow-origintajuk sebagai jawabannya.

heinob
sumber
Fungsi yang sangat baik! Memuat JavaScript sebelum JS tambahan apa pun ditulis setelah badan. Sangat penting saat memuat banyak skrip.
tfont
3
@heinob: Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js)
user2284570
@ user2284570: Jika Anda adalah pemilik domain asing: setel header `allow-origin 'pada jawaban server. Jika Anda bukan pemilik: tidak ada. Maaf! Itu adalah kebijakan lintas-asal.
heinob
2
@ user2284570: Saya mengerti komentar Anda dengan cara itu, bahwa Anda bukan pemilik domain tempat Anda ingin memuat skrip. Dalam hal ini Anda hanya dapat memuat skrip melalui <script>tag yang dimasukkan , bukan melalui XMLHttpRequest.
heinob
2
Bagi mereka yang berencana untuk menggunakan ini di Firefox (katakan untuk skrip imacros), tambahkan baris ini ke bagian atas file:const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
Kwestion
49

Saya baru saja menulis kode JavaScript ini (menggunakan Prototipe untuk manipulasi DOM ):

var require = (function() {
    var _required = {};
    return (function(url, callback) {
        if (typeof url == 'object') {
            // We've (hopefully) got an array: time to chain!
            if (url.length > 1) {
                // Load the nth file as soon as everything up to the
                // n-1th one is done.
                require(url.slice(0, url.length - 1), function() {
                    require(url[url.length - 1], callback);
                });
            } else if (url.length == 1) {
                require(url[0], callback);
            }
            return;
        }
        if (typeof _required[url] == 'undefined') {
            // Haven't loaded this URL yet; gogogo!
            _required[url] = [];

            var script = new Element('script', {
                src: url,
                type: 'text/javascript'
            });
            script.observe('load', function() {
                console.log("script " + url + " loaded.");
                _required[url].each(function(cb) {
                    cb.call(); // TODO: does this execute in the right context?
                });
                _required[url] = true;
            });

            $$('head')[0].insert(script);
        } else if (typeof _required[url] == 'boolean') {
            // We already loaded the thing, so go ahead.
            if (callback) {
                callback.call();
            }
            return;
        }

        if (callback) {
            _required[url].push(callback);
        }
    });
})();

Pemakaian:

<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
    require(['foo.js','bar.js'], function () {
        /* Use foo.js and bar.js here */
    });
</script>

Intisari: http://gist.github.com/284442 .

nornagon
sumber
7
jrburke menulis ini sebagai RequireJS. Github: requireejs.org/docs/requirements.html
Mike Caron
Bukankah ini menempatkan skrip yang dimuat di luar ruang lingkup yang membutuhkan () dipanggil? Sepertinya eval () adalah satu-satunya cara untuk melakukannya dalam ruang lingkup. Atau ada cara lain?
trusktr
44

Berikut adalah versi umum tentang cara Facebook melakukannya untuk tombol Suka di mana-mana:

<script>
  var firstScript = document.getElementsByTagName('script')[0],
      js = document.createElement('script');
  js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
  js.onload = function () {
    // do stuff with your dynamically loaded script
    snowStorm.snowColor = '#99ccff';
  };
  firstScript.parentNode.insertBefore(js, firstScript);
</script>

Jika itu berfungsi untuk Facebook, itu akan bekerja untuk Anda.

Alasan mengapa kami mencari scriptelemen pertama bukan headatau bodykarena beberapa browser tidak membuat satu jika hilang, tetapi kami dijamin memiliki scriptelemen - yang ini. Baca lebih lanjut di http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ .

Dan Dascalescu
sumber
3
Bagus sekali! Beberapa metode di sini juga berfungsi, tetapi di bawah pengaturan dinamis ini berfungsi paling baik.
tfont
saya memperluas skrip Anda untuk menghilangkan dublicate
Kamil Dąbrowski
39

Jika Anda ingin menggunakan JavaScript murni, Anda dapat menggunakannya document.write.

document.write('<script src="myscript.js" type="text/javascript"></script>');

Jika Anda menggunakan perpustakaan jQuery, Anda dapat menggunakan $.getScriptmetode ini.

$.getScript("another_script.js");
Venu immadi
sumber
8
tidak akan mendokumentasikan. Menulis menghapus yang lainnya?
Eisa Adil
30

Anda juga dapat merakit skrip Anda menggunakan PHP :

File main.js.php:

<?php
    header('Content-type:text/javascript; charset=utf-8');
    include_once("foo.js.php");
    include_once("bar.js.php");
?>

// Main JavaScript code goes here
Calmarius
sumber
16
Kedengarannya intinya adalah menyimpan semua ini dalam javascript di ujung depan
Ariel
1
Terima kasih sudah mengingatkan ini. Anda juga dapat meminta PHP menulis tag <script> di header HTML Anda, sehingga file js yang Anda butuhkan (dan hanya itu) akan dimuat.
Rolf
29

Sebagian besar solusi yang ditampilkan di sini menyiratkan pemuatan dinamis. Saya sedang mencari kompiler yang merakit semua file yang tergantung menjadi file output tunggal. Sama seperti Less / Sass preprocessors berurusan dengan aturan CSS @import. Karena saya tidak menemukan sesuatu yang layak seperti ini, saya menulis alat sederhana untuk menyelesaikan masalah ini.

Jadi di sini adalah kompiler, https://github.com/dsheiko/jsic , yang menggantikan $import("file-path")dengan konten file yang diminta dengan aman. Berikut ini adalah plugin Grunt yang sesuai : https://github.com/dsheiko/grunt-jsic .

Pada cabang master jQuery, mereka hanya menggabungkan file sumber atom menjadi satu mulai dengan intro.jsdan berakhir dengan outtro.js. Itu tidak cocok untuk saya karena tidak memberikan fleksibilitas pada desain kode sumber. Lihat cara kerjanya dengan jsic:

src / main.js

var foo = $import("./Form/Input/Tel");

src / Form / Input / Tel.js

function() {
    return {
          prop: "",
          method: function(){}
    }
}

Sekarang kita dapat menjalankan kompiler:

node jsic.js src/main.js build/mail.js

Dan dapatkan file gabungannya

build / main.js

var foo = function() {
    return {
          prop: "",
          method: function(){}
    }
};
Dmitry Sheiko
sumber
2
Sejak posting ini saya datang dengan solusi yang lebih baik - kompiler modul CommonJS - github.com/dsheiko/cjsc Jadi Anda cukup menulis modul CommonJs atau NodeJs dan mengakses satu sama lain namun menyimpannya dalam ruang lingkup yang terisolasi. Manfaat: Tidak perlu beberapa permintaan HTTP yang mempengaruhi kinerja Anda tidak perlu membungkus kode modul Anda secara manual - itu adalah tanggung jawab kompiler (jadi pembacaan kode sumber yang lebih baik) Anda tidak memerlukan pustaka eksternal apa pun. Ini kompatibel dengan UMD- dan modul NodeJs (mis. Anda dapat membahas jQuery, Backbone sebagai modul tanpa menyentuh kode mereka)
Dmitry Sheiko
26

Jika niat Anda untuk memuat file JavaScript menggunakan fungsi dari file yang diimpor / disertakan , Anda juga dapat mendefinisikan objek global dan mengatur fungsi sebagai item objek. Contohnya:

global.js

A = {};

file1.js

A.func1 = function() {
  console.log("func1");
}

file2.js

A.func2 = function() {
  console.log("func2");
}

main.js

A.func1();
A.func2();

Anda hanya perlu berhati-hati saat memasukkan skrip ke dalam file HTML. Urutannya harus seperti di bawah ini:

<head>
  <script type="text/javascript" src="global.js"></script>
  <script type="text/javascript" src="file1.js"></script>
  <script type="text/javascript" src="file2.js"></script>
  <script type="text/javascript" src="main.js"></script>
</head>
Adem İlhan
sumber
22

Ini harus dilakukan:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
tggagne
sumber
5
yang evaladalah apa yang salah dengan itu. Dari Crockford , " evaladalah kejahatan. evalFungsinya adalah fitur JavaScript yang paling banyak disalahgunakan. Hindari itu. evalAlias. Jangan gunakan Functionkonstruktor. Jangan berikan string ke setTimeoutatau setInterval." Jika Anda belum membaca "JavaScript: The Good Parts" -nya, maka keluarlah dan lakukan sekarang. Anda tidak akan menyesalinya.
MattDMo
13
@ MatDMo "Seseorang bilang itu buruk" sebenarnya bukan argumen.
Casey
4
@emodendroket Saya kira Anda tidak tahu siapa Douglas Crockford .
MattDMo
13
@ MatDMo Saya sepenuhnya sadar siapa dia, tapi dia manusia, bukan dewa.
Casey
2
@tggagne: Apa yang bisa saya lakukan agar berfungsi untuk lintas-domain? (memuat skrip dari http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js)
user2284570
21

Atau alih-alih termasuk pada saat dijalankan, gunakan skrip untuk menyatukan sebelum mengunggah.

Saya menggunakan Sprockets (saya tidak tahu apakah ada yang lain). Anda membuat kode JavaScript dalam file terpisah dan memasukkan komentar yang diproses oleh mesin Sprockets sebagai termasuk. Untuk pengembangan, Anda dapat memasukkan file secara berurutan, kemudian untuk produksi untuk menggabungkannya ...

Lihat juga:

JMawer
sumber
Browserify jauh lebih populer daripada Sprockets.
Dan Dascalescu
18

Saya punya masalah sederhana, tetapi saya bingung dengan jawaban atas pertanyaan ini.

Saya harus menggunakan variabel (myVar1) yang didefinisikan dalam satu file JavaScript (myvariables.js) di file JavaScript lain (main.js).

Untuk ini saya lakukan seperti di bawah ini:

Memuat kode JavaScript dalam file HTML, dalam urutan yang benar, myvariables.js pertama, lalu main.js:

<html>
    <body onload="bodyReady();" >

        <script src="myvariables.js" > </script>
        <script src="main.js" > </script>

        <!-- Some other code -->
    </body>
</html>

File: myvariables.js

var myVar1 = "I am variable from myvariables.js";

File: main.js

// ...
function bodyReady() {
    // ...
    alert (myVar1);    // This shows "I am variable from myvariables.js", which I needed
    // ...
}
// ...

Seperti yang Anda lihat, saya telah menggunakan variabel dalam satu file JavaScript di file JavaScript lain, tapi saya tidak perlu memasukkan satu ke yang lain. Saya hanya perlu memastikan bahwa file JavaScript pertama dimuat sebelum file JavaScript kedua, dan, variabel file JavaScript pertama dapat diakses di file JavaScript kedua, secara otomatis.

Ini menyelamatkan hari saya. Saya harap ini membantu.

Manohar Reddy Poreddy
sumber
Masalah dengan jawaban ini adalah tidak seperti itu import. Anda memerlukan file HTML untuk mendapatkan barang dari satu file js ke file lainnya.
Cannicide
Sangat benar. Itulah yang beberapa jawaban lain miliki sebagai solusi. Namun saya punya dua file JS, orang harus menggunakan variabel JS lainnya. Tidak ada node.js, next.js, express.js, dll, jadi impor ATAU mengharuskan tidak akan berfungsi, hanya memiliki file .js biasa.
Manohar Reddy Poreddy
Dapat dimengerti, bagaimanapun, pertanyaannya sebenarnya adalah meminta untuk mengimpor file javascript dalam file lain itu sendiri, bukan hanya mengakses variabel-variabelnya menggunakan file HTML. Misalnya, anggap Anda membuat fungsionalitas untuk sebuah tombol, dan Anda menggunakan tiga file js berbeda, satu untuk penanganan klik, satu untuk penanganan hover, satu untuk panggilan balik untuk masing-masing dari dua lainnya. Akan sangat membantu untuk mengimpor dua js lainnya di js ketiga itu sendiri, dan hanya memiliki satu <script>tag. Ini dapat membantu organisasi. Jawaban ini bukan pertanyaan yang diajukan, dan tidak ideal dalam konteks ini.
Cannicide
Ketika saya mencari solusi untuk masalah saya, saya mencari dengan cara yang benar, namun Google berpikir bahwa ini adalah halaman yang benar sehingga saya mendarat di sini. Itu sebabnya saya menulis jawaban saya di sini. Sepertinya, saya melakukannya dengan benar, karena 15 suara naik di atas. Untuk tidak menyia-nyiakan waktu orang lain, saya telah meletakkan awal yang jelas tentang apa skenario saya - telah menempatkan kode HTML pertama - yang sepertinya membantu, karena Anda menjawab & mengatakan html bukan skenario Anda. Harapan yang diklarifikasi.
Manohar Reddy Poreddy
Ya - memang sepertinya beberapa orang mencari masalah yang sedikit berbeda, di mana ini adalah solusi, dan menemukan ini. Meskipun ini belum tentu merupakan jawaban untuk pertanyaan ini, yang paling pasti adalah jawaban untuk pertanyaan lain yang serupa. Dengan demikian, tidak apa-apa untuk memiliki jawaban ini di sini karena membantu mereka yang mencari jawaban itu. Terima kasih atas balasan itu, itu mengklarifikasi.
Cannicide
16

Jika Anda menggunakan Pekerja Web dan ingin menyertakan skrip tambahan dalam lingkup pekerja, jawaban lain yang diberikan tentang menambahkan skrip ke headtag, dll. Tidak akan berfungsi untuk Anda.

Untungnya, Pekerja Web memiliki importScriptsfungsi mereka sendiri yang merupakan fungsi global dalam lingkup Pekerja Web, asli dari browser itu sendiri karena merupakan bagian dari spesifikasi .

Atau, sebagai jawaban tertinggi kedua untuk menyoroti pertanyaan Anda , RequireJS juga dapat menangani termasuk skrip di dalam Pekerja Web (kemungkinan memanggil importScriptsdirinya sendiri, tetapi dengan beberapa fitur bermanfaat lainnya).

Turnerj
sumber
16

Dalam bahasa modern dengan tanda centang apakah skrip telah dimuat akan menjadi:

function loadJs(url){
  return new Promise( (resolve, reject) => {
    if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
    const script = document.createElement("script")
    script.src = url
    script.onload = resolve
    script.onerror = reject
    document.head.appendChild(script)
  });
}

Penggunaan (async / menunggu):

try { await loadJs("https://.../script.js") } 
catch(error) {console.log(error)}

atau

await loadJs("https://.../script.js").catch(err => {})

Penggunaan (Janji):

loadJs("https://.../script.js").then(res => {}).catch(err => {})
Dmitry Sheiko
sumber
Bagus. Solusi yang bagus
Naftali alias Neal
Ringkas dan hanya membutuhkan ES5, dan secara elegan menghindari panggilan balik secara formal. Dmitry terima kasih!
Eureka
Wow, berfungsi di browser tanpa server. pi.js = sederhana var pi = 3.14. panggil fungsi loadJS () vialoadJs("pi.js").then(function(){ console.log(pi); });
zipzit
14

The @importsintaks untuk mencapai CSS-seperti mengimpor JavaScript adalah mungkin menggunakan alat seperti Campuran melalui khusus mereka .mixjenis file (lihat disini ). Saya membayangkan aplikasi hanya menggunakan salah satu metode yang disebutkan di atas secara internal, meskipun saya tidak tahu.

Dari dokumentasi Campuran pada .mixfile:

File campuran hanyalah file .js atau .css dengan .mix. dalam nama file. File campuran hanya memperluas fungsionalitas dari gaya normal atau file skrip dan memungkinkan Anda untuk mengimpor dan menggabungkan.

Berikut ini contoh .mixfile yang menggabungkan beberapa .jsfile menjadi satu:

// scripts-global.mix.js
// Plugins - Global

@import "global-plugins/headroom.js";
@import "global-plugins/retina-1.1.0.js";
@import "global-plugins/isotope.js";
@import "global-plugins/jquery.fitvids.js";

Campuran menghasilkan ini sebagai scripts-global.jsdan juga sebagai versi yang diperkecil (scripts-global.min.js ).

Catatan: Saya sama sekali tidak berafiliasi dengan Mixture, selain menggunakannya sebagai alat pengembangan front-end. Saya menemukan pertanyaan ini setelah melihat .mixfile JavaScript sedang beraksi (di salah satu boilerplture Campuran) dan sedikit bingung olehnya ("Anda bisa melakukan ini?" Saya berpikir sendiri). Kemudian saya menyadari bahwa itu adalah tipe file khusus aplikasi (agak mengecewakan, disetujui). Meskipun demikian, pikir pengetahuan itu mungkin bermanfaat bagi orang lain.

UPDATE : Campuran sekarang gratis (offline).

UPDATE : Campuran sekarang dihentikan. Rilis campuran lama masih tersedia

Isaac Gregson
sumber
Ini akan luar biasa jika itu adalah modul simpul.
B01
@ B01 Kedengarannya seperti tantangan;) Kalau saja aku punya waktu ... mungkin orang lain melakukannya?
Isaac Gregson
13
var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);
Sam4Code
sumber
2
Ini adalah kode paling sederhana, tetapi akan gagal dalam beberapa kasus tepi ketika bodybelum ada atau tidak dapat dimodifikasi. Juga membantu menjelaskan jawaban.
Dan Dascalescu
13

Metode saya yang biasa adalah:

var require = function (src, cb) {
    cb = cb || function () {};

    var newScriptTag = document.createElement('script'),
        firstScriptTag = document.getElementsByTagName('script')[0];
    newScriptTag.src = src;
    newScriptTag.async = true;
    newScriptTag.onload = newScriptTag.onreadystatechange = function () {
        (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());
    };
    firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);
}

Ini berfungsi dengan baik dan tidak menggunakan halaman-reload untuk saya. Saya sudah mencoba metode AJAX (salah satu jawaban lain) tetapi tampaknya tidak bekerja dengan baik untuk saya.

Berikut adalah penjelasan tentang bagaimana kode bekerja untuk mereka yang penasaran: pada dasarnya, ini membuat tag skrip baru (setelah yang pertama) dari URL. Ini mengaturnya ke mode asinkron sehingga tidak memblokir sisa kode, tetapi memanggil panggilan balik ketika readyState (keadaan konten yang akan dimuat) berubah menjadi 'dimuat'.

Christopher Dumas
sumber
13

Meskipun jawaban ini bagus, ada "solusi" sederhana yang telah ada sejak pemuatan skrip ada, dan itu akan mencakup 99,999% dari kasus penggunaan kebanyakan orang. Cukup sertakan skrip yang Anda butuhkan sebelum skrip yang membutuhkannya. Untuk sebagian besar proyek, tidak butuh waktu lama untuk menentukan skrip mana yang diperlukan dan dalam urutan apa.

<!DOCTYPE HTML>
<html>
    <head>
        <script src="script1.js"></script>
        <script src="script2.js"></script>
    </head>
    <body></body>
</html>

Jika script2 membutuhkan script1, ini benar-benar cara termudah untuk melakukan sesuatu seperti ini. Saya sangat terkejut tidak ada yang mengemukakan ini, karena ini adalah jawaban yang paling jelas dan paling sederhana yang akan diterapkan di hampir setiap kasus.

KthProg
sumber
1
Saya menduga banyak orang termasuk saya, kita perlu nama file dinamis.
Stuart McIntyre
1
@StuartMcIntyre dalam kasus itu, atur atribut src dari tag skrip saat runtime, dan tunggu acara onload (tentu saja ada solusi yang lebih baik dalam kasus itu pada tahun 2019).
KthProg
12

Saya menulis modul sederhana yang mengotomatiskan pekerjaan mengimpor / termasuk skrip modul dalam JavaScript. Untuk penjelasan rinci tentang kode, lihat posting blog JavaScript mengharuskan / impor / sertakan modul .

// ----- USAGE -----

require('ivar.util.string');
require('ivar.net.*');
require('ivar/util/array.js');
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js');

ready(function(){
    //Do something when required scripts are loaded
});

    //--------------------

var _rmod = _rmod || {}; //Require module namespace
_rmod.LOADED = false;
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
    scripts: {},
    length: 0
};

_rmod.findScriptPath = function(script_name) {
    var script_elems = document.getElementsByTagName('script');
    for (var i = 0; i < script_elems.length; i++) {
        if (script_elems[i].src.endsWith(script_name)) {
            var href = window.location.href;
            href = href.substring(0, href.lastIndexOf('/'));
            var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
            return url.substring(href.length+1, url.length);
        }
    }
    return '';
};

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark
                                                   //the root directory of your library, any library.


_rmod.injectScript = function(script_name, uri, callback, prepare) {

    if(!prepare)
        prepare(script_name, uri);

    var script_elem = document.createElement('script');
    script_elem.type = 'text/javascript';
    script_elem.title = script_name;
    script_elem.src = uri;
    script_elem.async = true;
    script_elem.defer = false;

    if(!callback)
        script_elem.onload = function() {
            callback(script_name, uri);
        };
    document.getElementsByTagName('head')[0].appendChild(script_elem);
};

_rmod.requirePrepare = function(script_name, uri) {
    _rmod.loading.scripts[script_name] = uri;
    _rmod.loading.length++;
};

_rmod.requireCallback = function(script_name, uri) {
    _rmod.loading.length--;
    delete _rmod.loading.scripts[script_name];
    _rmod.imported[script_name] = uri;

    if(_rmod.loading.length == 0)
        _rmod.onReady();
};

_rmod.onReady = function() {
    if (!_rmod.LOADED) {
        for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
            _rmod.on_ready_fn_stack[i]();
        });
        _rmod.LOADED = true;
    }
};

_.rmod = namespaceToUri = function(script_name, url) {
    var np = script_name.split('.');
    if (np.getLast() === '*') {
        np.pop();
        np.push('_all');
    }

    if(!url)
        url = '';

    script_name = np.join('.');
    return  url + np.join('/')+'.js';
};

//You can rename based on your liking. I chose require, but it
//can be called include or anything else that is easy for you
//to remember or write, except "import", because it is reserved
//for future use.
var require = function(script_name) {
    var uri = '';
    if (script_name.indexOf('/') > -1) {
        uri = script_name;
        var lastSlash = uri.lastIndexOf('/');
        script_name = uri.substring(lastSlash+1, uri.length);
    } 
    else {
        uri = _rmod.namespaceToUri(script_name, ivar._private.libpath);
    }

    if (!_rmod.loading.scripts.hasOwnProperty(script_name)
     && !_rmod.imported.hasOwnProperty(script_name)) {
        _rmod.injectScript(script_name, uri,
            _rmod.requireCallback,
                _rmod.requirePrepare);
    }
};

var ready = function(fn) {
    _rmod.on_ready_fn_stack.push(fn);
};
stamat
sumber
10

Script ini akan menambahkan file JavaScript ke atas <script>tag lain :

(function () {
    var li = document.createElement('script'); 
    li.type = 'text/javascript'; 
    li.src= "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; 
    li.async=true; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(li, s);
})();
Vicky Gonsalves
sumber
10

Ada juga Head.js . Sangat mudah untuk berurusan dengan:

head.load("js/jquery.min.js",
          "js/jquery.someplugin.js",
          "js/jquery.someplugin.css", function() {
  alert("Everything is ok!");
});

Seperti yang Anda lihat, ini lebih mudah daripada Require.js dan senyaman $.getScriptmetode jQuery . Ini juga memiliki beberapa fitur canggih, seperti pemuatan bersyarat, deteksi fitur dan banyak lagi .

Ale
sumber
10

Ada banyak jawaban potensial untuk pertanyaan ini. Jawaban saya jelas berdasarkan sejumlah dari mereka. Inilah yang akhirnya saya baca setelah membaca semua jawaban.

Masalah dengan $.getScriptdan benar-benar solusi lain yang memerlukan panggilan balik saat memuat selesai adalah bahwa jika Anda memiliki banyak file yang menggunakannya dan saling bergantung satu sama lain, Anda tidak lagi memiliki cara untuk mengetahui kapan semua skrip telah dimuat (setelah mereka disarangkan dalam banyak file).

Contoh:

file3.js

var f3obj = "file3";

// Define other stuff

file2.js:

var f2obj = "file2";
$.getScript("file3.js", function(){

    alert(f3obj);

    // Use anything defined in file3.
});

file1.js:

$.getScript("file2.js", function(){
    alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
    alert(f2obj);

    // Use anything defined in the loaded script...
});

Anda benar ketika mengatakan bahwa Anda dapat menentukan Ajax untuk berjalan secara sinkron atau menggunakan XMLHttpRequest , tetapi tren saat ini tampaknya untuk menolak permintaan sinkron, sehingga Anda mungkin tidak mendapatkan dukungan browser penuh sekarang atau di masa depan.

Anda dapat mencoba menggunakan $.whenuntuk memeriksa array objek yang ditangguhkan, tetapi sekarang Anda melakukan ini di setiap file dan file2 akan dianggap dimuat segera setelah $.whendieksekusi bukan ketika callback dieksekusi, jadi file1 masih melanjutkan eksekusi sebelum file3 dimuat . Ini benar-benar masih memiliki masalah yang sama.

Saya memutuskan untuk mundur daripada maju. Terima kasih document.writeln. Saya tahu itu hal yang tabu, tetapi selama digunakan dengan benar, ini bekerja dengan baik. Anda berakhir dengan kode yang dapat didebug dengan mudah, ditampilkan di DOM dengan benar dan dapat memastikan urutan ketergantungan dimuat dengan benar.

Anda tentu saja dapat menggunakan $ ("body"). Append (), tetapi kemudian Anda tidak dapat lagi melakukan debug dengan benar.

CATATAN: Anda harus menggunakan ini hanya saat halaman dimuat, jika tidak, Anda mendapatkan layar kosong. Dengan kata lain, selalu tempatkan ini sebelum / di luar dokumen . Sudah . Saya belum diuji menggunakan ini setelah halaman dimuat dalam acara klik atau semacamnya, tapi saya cukup yakin itu akan gagal.

Saya menyukai gagasan memperluas jQuery, tetapi jelas Anda tidak perlu melakukannya.

Sebelum menelepon document.writeln, ini memeriksa untuk memastikan skrip belum memuat dengan mengevaluasi semua elemen skrip.

Saya berasumsi bahwa skrip tidak sepenuhnya dieksekusi sampai document.readyacaranya telah dieksekusi. (Saya tahu menggunakan document.readytidak diperlukan, tetapi banyak orang menggunakannya, dan menangani ini adalah perlindungan.)

Ketika file-file tambahan dimuat, document.readycallback akan dieksekusi dalam urutan yang salah. Untuk mengatasi ini ketika skrip benar-benar dimuat, skrip yang mengimpornya diimpor kembali sendiri dan eksekusi dihentikan. Ini menyebabkan file asal sekarang memiliki document.readycallback yang dieksekusi setelah skrip apa pun yang diimpornya.

Alih-alih pendekatan ini, Anda bisa mencoba memodifikasi jQuery readyList, tetapi ini sepertinya solusi yang lebih buruk.

Larutan:

$.extend(true,
{
    import_js : function(scriptpath, reAddLast)
    {
        if (typeof reAddLast === "undefined" || reAddLast === null)
        {
            reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
        }

        var found = false;
        if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
        {
            found = $('script').filter(function () {
                return ($(this).attr('src') == scriptpath);
            }).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
        }

        if (found == false) {

            var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.

            document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln

            if (reAddLast)
            {
                $.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
                throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
            }
            return true;
        }
        return false;
    }
});

Pemakaian:

File3:

var f3obj = "file3";

// Define other stuff
$(function(){
    f3obj = "file3docready";
});

File2:

$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
    f2obj = "file2docready";
});

File1:

$.import_js('js/file2.js');

// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"

$(function(){
    // Use objects from file2 or file3 some more.
    alert(f3obj); //"file3docready"
    alert(f2obj); //"file2docready"
});
curlyhairedgenius
sumber
Inilah yang dinyatakan oleh jawaban yang saat ini diterima: tidak cukup.
Cannicide
Perbedaan utama adalah bahwa jika ada dependensi yang hilang itu akan menambahkan tag skrip untuk dependensi, kemudian juga menambahkan tag skrip untuk file panggilan, dan melemparkan kesalahan yang menghentikan eksekusi. Ini menyebabkan skrip diproses dan dijalankan dalam urutan yang benar dan menghilangkan kebutuhan akan callback. Jadi skrip dependen akan dimuat dan dieksekusi sebelum skrip panggilan sambil mendukung nesting.
curlyhairedgenius
Mengenai "tren saat ini tampaknya untuk menghilangkan permintaan sinkron," ini benar hanya karena banyak pengembang telah menyalahgunakannya dan membuat pengguna menunggu tanpa perlu. Namun, jika permintaan secara alami sinkron, seperti pernyataan Sertakan, maka Ajax sinkron sederhana baik-baik saja. Saya membuat fungsi ekstensi JavaScript umum yang secara sinkron menjalankan fungsi seperti membaca file yang bukan bagian dari JavaScript dengan menjalankan file PHP "server", dan merasa sangat berguna ketika menulis aplikasi menggunakan JavaScript. Server web lokal tidak diperlukan untuk Ajax tersebut.
David Spector
10

Ada beberapa cara untuk mengimplementasikan modul dalam Javascript, Berikut adalah 2 yang paling populer:

Modul ES6

Browser belum mendukung sistem moduling ini sehingga agar Anda dapat menggunakan sintaks ini, Anda harus menggunakan bundler seperti webpack. Lagi pula, menggunakan bundler lebih baik karena ini dapat menggabungkan semua file Anda yang berbeda menjadi satu (atau beberapa pasangan) file. Ini akan melayani file-file dari server ke klien lebih cepat karena setiap permintaan HTTP memiliki beberapa overhead terkait yang menyertainya. Jadi dengan mengurangi permintaan HTTP secara keseluruhan, kami meningkatkan kinerjanya. Berikut adalah contoh modul ES6:

// main.js file

export function add (a, b) {
  return a + b;
}

export default function multiply (a, b) {
  return a * b;
}


// test.js file

import {add}, multiply from './main';   // for named exports between curly braces {export1, export2}
                                        // for default exports without {}

console.log(multiply(2, 2));  // logs 4

console.log(add(1, 2));  // logs 3

CommonJS (digunakan dalam NodeJS)

Sistem moduling ini digunakan di NodeJS. Anda pada dasarnya menambahkan ekspor Anda ke objek yang disebut module.exports. Anda kemudian dapat mengakses objek ini melalui a require('modulePath'). Penting di sini adalah untuk menyadari bahwa modul-modul ini sedang di-cache, jadi jika Anda require()modul tertentu dua kali akan mengembalikan modul yang sudah dibuat.

// main.js file

function add (a, b) {
  return a + b;
}

module.exports = add;  // here we add our add function to the exports object


// test.js file

const add = require('./main'); 

console.log(add(1,2));  // logs 3
Willem van der Veen
sumber
9

Saya sampai pada pertanyaan ini karena saya sedang mencari cara sederhana untuk memelihara koleksi plugin JavaScript yang berguna. Setelah melihat beberapa solusi di sini, saya datang dengan ini:

  1. Siapkan file yang disebut "plugins.js" (atau extensions.js atau apa pun yang Anda inginkan). Simpan file plugin Anda bersama dengan satu file master itu.

  2. plugins.js akan memiliki array bernama pluginNames[]yang akan kita iterate each(), kemudian tambahkan <script>tag ke kepala untuk setiap plugin

//set array to be updated when we add or remove plugin files
var pluginNames = ["lettering", "fittext", "butterjam", etc.];

//one script tag for each plugin
$.each(pluginNames, function(){
    $('head').append('<script src="js/plugins/' + this + '.js"></script>');
});
  1. Panggil hanya satu file di kepala Anda secara manual:
    <script src="js/plugins/plugins.js"></script>

TAPI:

Meskipun semua plugin dimasukkan ke tag kepala seperti seharusnya, mereka tidak selalu dijalankan oleh browser saat Anda mengklik halaman atau menyegarkan.

Saya menemukan ini lebih dapat diandalkan untuk hanya menulis tag skrip di PHP. Anda hanya perlu menulisnya sekali dan itu sama artinya dengan memanggil plugin menggunakan JavaScript.

rgb_life
sumber
@ akan, solusi Anda terlihat jauh lebih bersih daripada saya dan saya khawatir saya mungkin memiliki beberapa kesalahan jika saya menggunakan milik saya, karena memanfaatkan. append (). Jadi untuk menggunakan ini, Anda bisa memanggil fungsi itu sekali saja untuk setiap file plugin yang ingin Anda sertakan?
rgb_life