Tự động tải một tệp JavaScript


167

Làm thế nào bạn có thể tải một cách đáng tin cậy và động một tệp JavaScript? Điều này có thể được sử dụng để triển khai một mô-đun hoặc thành phần mà khi 'khởi tạo', thành phần đó sẽ tự động tải tất cả các tập lệnh thư viện JavaScript cần thiết theo yêu cầu.

Máy khách sử dụng thành phần không bắt buộc phải tải tất cả các tệp tập lệnh thư viện (và chèn <script>thẻ theo cách thủ công vào trang web của chúng) thực hiện thành phần này - chỉ là tệp tập lệnh thành phần 'chính'.

Làm cách nào để các thư viện JavaScript chính thực hiện điều này (Prototype, jQuery, v.v.)? Các công cụ này có hợp nhất nhiều tệp JavaScript thành một phiên bản 'xây dựng' có thể phân phối lại của một tệp tập lệnh không? Hay họ có thực hiện bất kỳ tải động nào của các tập lệnh 'thư viện' phụ trợ không?

Một bổ sung cho câu hỏi này: có cách nào để xử lý sự kiện sau khi tệp JavaScript được bao gồm động được tải không? Nguyên mẫu có document.observecho các sự kiện toàn tài liệu. Thí dụ:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

Các sự kiện có sẵn cho một yếu tố kịch bản là gì?


Câu trả lời:


84

Bạn có thể viết các thẻ script động (sử dụng Prototype ):

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

Vấn đề ở đây là chúng ta không biết khi nào tệp script bên ngoài được tải đầy đủ.

Chúng tôi thường muốn mã phụ thuộc của mình trên dòng tiếp theo và muốn viết một cái gì đó như:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

Có một cách thông minh để tiêm phụ thuộc tập lệnh mà không cần gọi lại. Bạn chỉ cần kéo tập lệnh thông qua yêu cầu AJAX đồng bộ và đánh giá tập lệnh ở cấp độ toàn cầu.

Nếu bạn sử dụng Prototype, phương thức Script.load trông như thế này:

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};

Tôi có thể làm gì để nó hoạt động cho tên miền chéo? (tải tập lệnh từ http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570


@Ciastopiekarz: Tôi không kiểm soát web.archive.org.
dùng2284570

Sau đó, bạn phải cạo dữ liệu bạn muốn truy cập bằng một số chương trình khác và cung cấp cho chính mình
David Schumann

Ajax.Request là gì ??
bluejayke

72

Không có nhập / bao gồm / yêu cầu trong javascript, nhưng có hai cách chính để đạt được những gì bạn muốn:

1 - Bạn có thể tải nó bằng một cuộc gọi AJAX sau đó sử dụng eval.

Đây là cách đơn giản nhất nhưng nó bị giới hạn trong miền của bạn vì cài đặt an toàn Javascript và sử dụng eval đang mở ra cánh cửa cho các lỗi và hack.

2 - Thêm thẻ tập lệnh với URL tập lệnh trong HTML.

Chắc chắn là cách tốt nhất để đi. Bạn có thể tải tập lệnh ngay cả từ máy chủ nước ngoài và nó hoàn toàn sạch khi bạn sử dụng trình phân tích cú pháp trình duyệt để đánh giá mã. Bạn có thể đặt thẻ vào đầu trang web hoặc ở dưới cùng của cơ thể.

Cả hai giải pháp này đều được thảo luận và minh họa ở đây.

Bây giờ, có một vấn đề lớn bạn phải biết về. Làm điều đó ngụ ý rằng bạn tải mã từ xa. Các trình duyệt web hiện đại sẽ tải tệp và tiếp tục thực thi tập lệnh hiện tại của bạn vì chúng tải mọi thứ không đồng bộ để cải thiện hiệu suất.

Điều đó có nghĩa là nếu bạn sử dụng các thủ thuật này trực tiếp, bạn sẽ không thể sử dụng mã mới được tải của mình dòng tiếp theo sau khi bạn yêu cầu nó được tải, bởi vì nó sẽ vẫn đang tải.

EG: my_lovely_script.js chứa 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

Sau đó, bạn tải lại trang nhấn F5. Và nó hoạt động! Gây nhầm lẫn...

Vậy giờ làm gì với nó ?

Chà, bạn có thể sử dụng bản hack mà tác giả gợi ý trong liên kết tôi đưa cho bạn. Tóm lại, đối với những người vội vàng, anh ta sử dụng en event để chạy chức năng gọi lại khi tập lệnh được tải. Vì vậy, bạn có thể đặt tất cả mã bằng thư viện từ xa trong chức năng gọi lại. VÍ DỤ :

function loadScript(url, callback)
{
    // adding the script tag to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   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);
}

Sau đó, bạn viết mã bạn muốn sử dụng SAU kịch bản được tải trong hàm lambda:

var myPrettyCode = function() {
    // here, do what ever you want
};

Sau đó, bạn chạy tất cả:

loadScript("my_lovely_script.js", myPrettyCode);

Ok, tôi hiểu rồi Nhưng đó là một nỗi đau để viết tất cả những thứ này.

Chà, trong trường hợp đó, bạn có thể sử dụng luôn luôn khung công tác jQuery miễn phí tuyệt vời, cho phép bạn thực hiện điều tương tự trong một dòng:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});

11
không thể tin được làm thế nào đánh giá thấp câu trả lời này. Cảm ơn bạn.
naftalimich

2
Tôi cá là vì mọi người không thích đọc qua dòng đầu tiên, trừ khi họ hứa rằng họ sẽ giàu nếu họ "chỉ cần làm theo ba bước bí mật này để thành công."
Costa

Những công việc này. Tôi hy vọng chia sẻ kinh nghiệm của tôi ở đây giúp tiết kiệm thời gian của bạn vì tôi đã dành nhiều giờ cho việc này. Tôi đang sử dụng Angular 6 và mẫu được áp dụng (html, css, jquery) Vấn đề là mẫu có tệp js tải sau khi các phần tử html được tải để đính kèm các sự kiện của người nghe. Tập tin js đó rất khó thực hiện sau khi tải ứng dụng góc. Thêm nó vào thẻ script ứng dụng góc (angular.json) sẽ gói chúng nhưng không thực thi tệp js đó sau khi tải. Đó là quá nhiều mã để viết lại trong bản in nên đây là sự trợ giúp tuyệt vời. Nhận xét tiếp theo Tôi sẽ đưa ra ví dụ về độ dài bình luận
Nour Lababidi

Tôi chỉ đơn giản sử dụng mã này như sau: ngAfterViewInit () {debugger; $ .getScript ("/ nội dung / js / jquery.app.js", function () {alert ("Tập lệnh được tải và thực thi."); // tại đây bạn có thể sử dụng bất cứ điều gì bạn đã xác định trong tập lệnh đã tải}); }
Nour Lababidi

Đối với '$' trong góc, tôi đã làm theo điều này: stackoverflow.com/questions/32050645/NH
Nour Lababidi

28

Gần đây tôi đã sử dụng một phiên bản ít phức tạp hơn với jQuery :

<script src="scripts/jquery.js"></script>
<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  var $head = $("head");
  for (var i = 0; i < js.length; i++) {
    $head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

Nó hoạt động rất tốt trong mọi trình duyệt mà tôi đã thử nghiệm trong: IE6 / 7, Firefox, Safari, Opera.

Cập nhật: Phiên bản không có jQuery:

<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  for (var i = 0, l = js.length; i < l; i++) {
    document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

25
Điều đó thật tuyệt ... trừ khi bạn đang cố gắng tải jquery.

1
Có vẻ như jQuery sẽ đưa plugin Yêu cầu vào jQuery Core để phát hành trong tương lai: plugins.jquery.com/project/require
Adam

1
Một cách thậm chí tốt hơn để sử dụng jQuery là sử dụng $.getScript. Xem câu trả lời của tôi.
Muhd

1
Modernizr (yepnope.js) hoặc lab.js là những giải pháp thích hợp cho việc này. sử dụng thư viện tập lệnh nặng (phải tải trước) không phải là câu trả lời phù hợp nhất cho thiết bị di động hoặc nhiều tình huống khác.
1nfiniti

2
@MaulikGangani trình duyệt cũ và trình xác nhận html sẽ diễn giải đó là mã thông báo để kết thúc tập lệnh.
ngày

20

Về cơ bản, tôi đã làm điều tương tự như bạn đã làm với Adam, nhưng với một sửa đổi nhỏ để đảm bảo rằng tôi đang gắn thẻ đầu để hoàn thành công việc. Tôi chỉ đơn giản là tạo một hàm bao gồm (mã bên dưới) để xử lý cả tập tin script và css.

Hàm này cũng kiểm tra để đảm bảo rằng tập lệnh hoặc tệp CSS chưa được tải động. Nó không kiểm tra các giá trị được mã hóa bằng tay và có thể có một cách tốt hơn để làm điều đó, nhưng nó phục vụ mục đích.

function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
        return;

    // Determine the MIME-type
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
        if( jsExpr.test( url ) )
            type = 'text/javascript';
        else if( cssExpr.test( url ) )
            type = 'text/css';

    // Create the appropriate element.
    var tag = null;
    switch( type ){
        case 'text/javascript' :
            tag = document.createElement( 'script' );
            tag.type = type;
            tag.src = url;
            break;
        case 'text/css' :
            tag = document.createElement( 'link' );
            tag.rel = 'stylesheet';
            tag.type = type;
            tag.href = url;
            break;
    }

    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
}

Không có nhiều bối cảnh hơn Pickle đó, tôi sợ rằng tôi không có bất kỳ đề xuất nào. Mã ở trên hoạt động như vốn có, nó được lấy trực tiếp từ một dự án hoạt động.
nhợt nhạt

5
@palehorse, Mike và Muhd, đúng, nó có thể hoạt động trong dự án của bạn, nhưng đó là vì các biến "gộpFile" và "Array" phải được định nghĩa ở nơi khác trong dự án của bạn, mã này sẽ không chạy, nó có thể chạy tốt hơn để chỉnh sửa nó để nó có thể hoạt động bên ngoài bối cảnh của dự án của bạn hoặc ít nhất là thêm một nhận xét giải thích những biến không xác định đó là gì (loại, v.v.)
user280109

14

một câu trả lời tuyệt vời khác

$.getScript("my_lovely_script.js", function(){


   alert("Script loaded and executed.");
  // here you can use anything you defined in the loaded script

 });

https://stackoverflow.com/a/950146/671046


2
Tôi có thể làm gì để nó hoạt động cho tên miền chéo? (tải tập lệnh từ http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

9

Dưới đây là một số mã ví dụ tôi đã tìm thấy ... có ai có cách tốt hơn không?

  function include(url)
  {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    var nodes = document.getElementsByTagName("*");
    var node = nodes[nodes.length -1].parentNode;
    node.appendChild(s);
  }

Tôi có thể làm gì để nó hoạt động cho tên miền chéo? (tải tập lệnh từ http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

6

Nếu bạn đã tải jQuery, bạn nên sử dụng $ .getScript .

Điều này có một lợi thế so với các câu trả lời khác ở đây là bạn có chức năng gọi lại tích hợp (để đảm bảo tập lệnh được tải trước khi mã phụ thuộc chạy) và bạn có thể kiểm soát bộ đệm.


4

Nếu bạn muốn tải tập lệnh SYNC , bạn cần thêm văn bản tập lệnh trực tiếp vào thẻ HTML CHÍNH. Thêm nó vào sẽ kích hoạt tải ASYNC . Để tải văn bản tập lệnh từ tệp bên ngoài một cách đồng bộ, hãy sử dụng XHR. Bên dưới một mẫu nhanh (nó đang sử dụng các phần của câu trả lời khác trong bài viết này và các bài đăng khác):

/*sample requires an additional method for array prototype:*/

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],

LoadFile: function (url) {
    var self = this;
    if (this.LoadedFiles.contains(url)) return;

    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                self.LoadedFiles.push(url);
                self.AddScript(xhr.responseText);
            } else {
                if (console) console.error(xhr.statusText);
            }
        }
    };
    xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
    xhr.send(null);
},

AddScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}
};

/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/

ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });

3

Có ai có cách tốt hơn không?

Tôi nghĩ rằng chỉ cần thêm tập lệnh vào phần thân sẽ dễ dàng hơn sau đó thêm tập lệnh vào nút cuối cùng trên trang. Còn cái này thì sao:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}

Tôi có thể làm gì để nó hoạt động cho tên miền chéo? (tải tập lệnh từ http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

Tôi đã sử dụng một giải pháp khác mà tôi tìm thấy trên mạng ... giải pháp này thuộc về những người sáng tạo và nó kiểm tra xem nguồn có được bao gồm trước khi gọi hàm không ...

bạn có thể tìm thấy tệp ở đây: include.js

/** include - including .js files from JS - bfults@gmail.com - 2005-02-09
 ** Code licensed under Creative Commons Attribution-ShareAlike License 
 ** http://creativecommons.org/licenses/by-sa/2.0/
 **/              
var hIncludes = null;
function include(sURI)
{   
  if (document.getElementsByTagName)
  {   
    if (!hIncludes)
    {
      hIncludes = {}; 
      var cScripts = document.getElementsByTagName("script");
      for (var i=0,len=cScripts.length; i < len; i++)
        if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
    }
    if (!hIncludes[sURI])
    {
      var oNew = document.createElement("script");
      oNew.type = "text/javascript";
      oNew.src = sURI;
      hIncludes[sURI]=true;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }   
} 

Tôi có thể làm gì để nó hoạt động cho tên miền chéo? (tải tập lệnh từ http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

Chỉ cần tìm hiểu về một tính năng tuyệt vời trong YUI 3 (tại thời điểm viết có sẵn trong bản phát hành xem trước). Bạn có thể dễ dàng chèn phụ thuộc vào thư viện YUI và các mô-đun "bên ngoài" (thứ bạn đang tìm kiếm) mà không cần quá nhiều mã: Trình tải YUI .

Nó cũng trả lời câu hỏi thứ hai của bạn về chức năng được gọi ngay khi mô-đun bên ngoài được tải.

Thí dụ:

YUI({
    modules: {
        'simple': {
            fullpath: "http://example.com/public/js/simple.js"
        },
        'complicated': {
            fullpath: "http://example.com/public/js/complicated.js"
            requires: ['simple']  // <-- dependency to 'simple' module
        }
    },
    timeout: 10000
}).use('complicated', function(Y, result) {
    // called as soon as 'complicated' is loaded
    if (!result.success) {
        // loading failed, or timeout
        handleError(result.msg);
    } else {
        // call a function that needs 'complicated'
        doSomethingComplicated(...);
    }
});

Làm việc hoàn hảo cho tôi và có lợi thế quản lý các phụ thuộc. Tham khảo tài liệu YUI để biết ví dụ với lịch YUI 2 .


Điều này có lẽ là lý tưởng ngoại trừ YUI bị che khuất rất lớn chỉ với chức năng này.
Muhd

3

Có một tiêu chuẩn ECMA mới được đề xuất gọi là nhập động , gần đây được tích hợp vào Chrome và Safari.

const moduleSpecifier = './dir/someModule.js';

import(moduleSpecifier)
   .then(someModule => someModule.foo()); // executes foo method in someModule

2

Kỹ thuật chúng tôi sử dụng tại nơi làm việc là yêu cầu tệp javascript sử dụng yêu cầu AJAX và sau đó trả lại () eval (). Nếu bạn đang sử dụng thư viện nguyên mẫu, họ sẽ hỗ trợ chức năng này trong cuộc gọi Ajax.Request của họ.


2

jquery đã giải quyết điều này cho tôi với hàm .append () của nó - đã sử dụng điều này để tải gói ui jquery hoàn chỉnh

/*
 * FILENAME : project.library.js
 * USAGE    : loads any javascript library
 */
    var dirPath = "../js/";
    var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];

    for(var script in library){
        $('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
    }

Để sử dụng - trong phần đầu html / php / etc của bạn sau khi bạn nhập jquery.js, bạn sẽ chỉ bao gồm một tệp này để tải toàn bộ thư viện của bạn nối nó vào đầu ...

<script type="text/javascript" src="project.library.js"></script>

2

Giữ cho nó đẹp, ngắn, đơn giản và có thể bảo trì! :]

// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library 
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

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

 // initialize a single load 
load('plugins/script.js');

// initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

Mã này chỉ đơn giản là một ví dụ chức năng ngắn có thể yêu cầu chức năng tính năng bổ sung để hỗ trợ đầy đủ trên bất kỳ nền tảng (hoặc đã cho) nào.


2

Nhập mô-đun động đã hạ cánh trong Firefox 67+ .

(async () => {
   await import('./synth/BubbleSynth.js')
})()

Với xử lý lỗi:

(async () => {
    await import('./synth/BubbleSynth.js').catch((error) => console.log('Loading failed' + error))
})()

Nó cũng hoạt động cho bất kỳ loại thư viện không phải mô-đun nào, trong trường hợp này lib có sẵn trên đối tượng cửa sổ, theo cách cũ, nhưng chỉ theo yêu cầu, là tốt.

Ví dụ sử dụng suncalc.js , máy chủ phải kích hoạt CORS để hoạt động theo cách này!

(async () => {
 await import('https://cdnjs.cloudflare.com/ajax/libs/suncalc/1.8.0/suncalc.min.js')
 .then(function(){
   let times = SunCalc.getTimes(new Date(), 51.5,-0.1);
   console.log("Golden Hour today in London: " + times.goldenHour.getHours() + ':' + times.sunrise.getMinutes() + ". Take your pics!")
  })
})()

https://caniuse.com/#feat=es6-module-dynamic-import


1

Có những kịch bản được thiết kế đặc biệt cho mục đích này.

yepnope.js được tích hợp vào Modernizr và lab.js là phiên bản tối ưu hơn (nhưng ít thân thiện với người dùng hơn.

Tôi sẽ không đề xuất việc này thông qua một thư viện lớn như jquery hoặc nguyên mẫu - bởi vì một trong những lợi ích chính của trình tải tập lệnh là khả năng tải tập lệnh sớm - bạn không cần phải đợi cho đến khi jquery & tất cả các phần tử dom của bạn tải trước chạy một kiểm tra để xem nếu bạn muốn tải động một tập lệnh.


1

Tôi đã viết một mô-đun đơn giản tự động hóa công việc nhập / bao gồm các tập lệnh mô-đun trong JavaScript. Hãy thử và xin vui lòng dành một số thông tin phản hồi! :) Để được giải thích chi tiết về mã tham khảo bài đăng trên blog này: http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/

var _rmod = _rmod || {}; //require module namespace
_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;
    }
};

//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 np = script_name.split('.');
    if (np[np.length-1] === '*') {
        np.pop();
        np.push('_all');
    }

    script_name = np.join('.');
    var uri = _rmod.libpath + np.join('/')+'.js';
    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);
};

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

require('ivar.util.array');
require('ivar.util.string');
require('ivar.net.*');

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

1

Tôi bị mất trong tất cả các mẫu này nhưng hôm nay tôi cần tải một .js bên ngoài từ .js chính của mình và tôi đã làm điều này:

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");

bạn có thể xem liên kết: answer
asmmahmud

1

Đây là một cách đơn giản với hỗ trợ gọi lại và IE:

function loadScript(url, callback) {

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState) { //IE
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        };
    } else { //Others
        script.onload = function () {
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

loadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {

     //jQuery loaded
     console.log('jquery loaded');

});

1

Tôi biết câu trả lời của tôi hơi muộn cho câu hỏi này, nhưng, đây là một bài viết tuyệt vời trong www.html5rocks.com - Đi sâu vào vùng nước âm u của tải tập lệnh .

Trong bài viết đó, kết luận rằng liên quan đến hỗ trợ trình duyệt, cách tốt nhất để tải động tệp JavaScript mà không chặn kết xuất nội dung là cách sau:

Xem xét bốn tập lệnh có tên script1.js, script2.js, script3.js, script4.jsthì bạn có thể thực hiện bằng cách áp dụng 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);
});

Bây giờ, Spec nói : Tải xuống cùng nhau, thực hiện theo thứ tự ngay khi tất cả tải xuống.

Firefox <3.6, Opera nói: Tôi không có ý tưởng gì về điều này async, đó là gì, nhưng thật ra tôi đã thực thi các tập lệnh được thêm vào thông qua JS theo thứ tự chúng được thêm vào.

Safari 5.0 cho biết: Tôi hiểu về mối quan hệ của Async, nhưng không hiểu cách đặt nó thành Hồi sai với JS. Tôi sẽ thực thi các tập lệnh của bạn ngay khi chúng hạ cánh, theo bất kỳ thứ tự nào.

IE <10 nói: Không có ý tưởng nào về dịch vụ as async, nhưng có một cách giải quyết bằng cách sử dụng trên mạng onreadystatechange.

Mọi thứ khác nói: Tôi là bạn của bạn, chúng tôi sẽ làm điều này bằng cuốn sách.

Bây giờ, mã đầy đủ với IE <10 cách giải quyết:

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

Một vài thủ thuật và thu nhỏ sau, nó là 362 byte

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
  "//other-domain.com/1.js",
  "2.js"
])

Tôi đang sử dụng cách tiếp cận trên, nó hoạt động tốt trong chrome & firefox nhưng gặp phải sự cố trong trình duyệt IE
Ông Roshan

1

Một cái gì đó như thế này ...

<script>
     $(document).ready(function() {
          $('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer><\/script>');
     });
</script>

1

Đây là một ví dụ đơn giản cho một hàm để tải các tệp JS. Các điểm liên quan:

  • bạn không cần jQuery, vì vậy ban đầu bạn có thể sử dụng tệp này để tải tệp jQuery.js
  • nó không đồng bộ với gọi lại
  • nó đảm bảo nó chỉ tải một lần, vì nó giữ một bao vây với bản ghi các url được tải, do đó tránh sử dụng mạng
  • trái với jQuery $.ajaxhoặc $.getScriptbạn có thể sử dụng nonces, giải quyết các vấn đề với CSP unsafe-inline. Chỉ cần sử dụng tài sảnscript.nonce
var getScriptOnce = function() {

    var scriptArray = []; //array of urls (closure)

    //function to defer loading of script
    return function (url, callback){
        //the array doesn't have such url
        if (scriptArray.indexOf(url) === -1){

            var script=document.createElement('script');
            script.src=url;
            var head=document.getElementsByTagName('head')[0],
                done=false;

            script.onload=script.onreadystatechange = function(){
                if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                    done=true;
                    if (typeof callback === 'function') {
                        callback();
                    }
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                    scriptArray.push(url);
                }
            };

            head.appendChild(script);
        }
    };
}();

Bây giờ bạn sử dụng nó đơn giản bằng cách

getScriptOnce("url_of_your_JS_file.js");

1

Một lớp lót vô lý, đối với những người nghĩ rằng tải thư viện js không nên lấy nhiều hơn một dòng mã: P

await new Promise((resolve, reject) => {let js = document.createElement("script"); js.src="mylibrary.js"; js.onload=resolve; js.onerror=reject; document.body.appendChild(js)});

Rõ ràng nếu tập lệnh bạn muốn nhập là một mô-đun, bạn có thể sử dụng import(...)chức năng.


1

Với Promise bạn có thể đơn giản hóa nó như thế này. Chức năng nạp:

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

Cách sử dụng (async / await):

await loadCDN("https://.../script.js")

Cách sử dụng (Hứa hẹn):

loadCDN("https://.../script.js").then(res => {}).catch(err => {})

LƯU Ý: có một giải pháp tương tự nhưng nó không kiểm tra xem tập lệnh đã được tải chưa và tải tập lệnh mỗi lần. Cái này kiểm tra thuộc tính src.


0

tất cả các thư viện javascript chính như jscript, nguyên mẫu, YUI đều hỗ trợ tải tập tin script. Ví dụ: trong YUI, sau khi tải lõi, bạn có thể thực hiện các thao tác sau để tải điều khiển lịch

var loader = new YAHOO.util.YUILoader({

    require: ['calendar'], // what components?

    base: '../../build/',//where do they live?

    //filter: "DEBUG",  //use debug versions (or apply some
                        //some other filter?

    //loadOptional: true, //load all optional dependencies?

    //onSuccess is the function that YUI Loader
    //should call when all components are successfully loaded.
    onSuccess: function() {
        //Once the YUI Calendar Control and dependencies are on
        //the page, we'll verify that our target container is 
        //available in the DOM and then instantiate a default
        //calendar into it:
        YAHOO.util.Event.onAvailable("calendar_container", function() {
            var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
            myCal.render();
        })
     },

    // should a failure occur, the onFailure function will be executed
    onFailure: function(o) {
        alert("error: " + YAHOO.lang.dump(o));
    }

 });

// Calculate the dependency and insert the required scripts and css resources
// into the document
loader.insert();

bạn có thể xem liên kết: answer
asmmahmud

0

Tôi đã điều chỉnh một số bài viết ở trên với ví dụ làm việc. Ở đây chúng ta có thể cung cấp css và js trong cùng một mảng.

$(document).ready(function(){

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/* define object that will wrap our logic */
var jsScriptCssLoader = {

jsExpr : new RegExp( "js$", "i" ),
cssExpr : new RegExp( "css$", "i" ),
loadedFiles: [],

loadFile: function (cssJsFileArray) {
    var self = this;
    // remove duplicates with in array
    cssJsFileArray.filter((item,index)=>cssJsFileArray.indexOf(item)==index)
    var loadedFileArray = this.loadedFiles;
    $.each(cssJsFileArray, function( index, url ) {
            // if multiple arrays are loaded the check the uniqueness
            if (loadedFileArray.contains(url)) return;
            if( self.jsExpr.test( url ) ){
                $.get(url, function(data) {
                    self.addScript(data);
                });

            }else if( self.cssExpr.test( url ) ){
                $.get(url, function(data) {
                    self.addCss(data);
                });
            }

            self.loadedFiles.push(url);
    });

    // don't load twice accross different arrays

},
addScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
},
addCss: function (code) {
    var oNew = document.createElement("style");
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}

};


//jsScriptCssLoader.loadFile(["css/1.css","css/2.css","css/3.css"]);
jsScriptCssLoader.loadFile(["js/common/1.js","js/2.js","js/common/file/fileReader.js"]);
});

0

Đối với những người bạn, những người yêu thích một lớp lót:

import('./myscript.js');

Rất có thể bạn có thể gặp lỗi, như:

Truy cập vào tập lệnh tại ' http: //..../myscript.js ' từ nguồn gốc ' http://127.0.0.1 ' đã bị chặn bởi chính sách CORS: Không có tiêu đề 'Access-Control-Allow-Origin' trên tài nguyên được yêu cầu.

Trong trường hợp đó, bạn có thể dự phòng:

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.