Làm thế nào để tải các tập lệnh bên ngoài một cách linh hoạt trong Angular?


150

Tôi có mô-đun này cấu thành thư viện bên ngoài cùng với logic bổ sung mà không cần thêm <script>thẻ trực tiếp vào index.html:

import 'http://external.com/path/file.js'
//import '../js/file.js'

@Component({
    selector: 'my-app',
    template: `
        <script src="http://iknow.com/this/does/not/work/either/file.js"></script>
        <div>Template</div>`
})
export class MyAppComponent {...}

Tôi nhận thấy thông số importkỹ thuật ES6 là tĩnh và được giải quyết trong quá trình chuyển mã TypeScript chứ không phải trong thời gian chạy.

Dù sao để làm cho nó có thể định cấu hình để file.js sẽ được tải từ CDN hoặc thư mục cục bộ? Làm thế nào để nói với Angular 2 để tải một kịch bản động?


Câu trả lời:


61

Nếu bạn đang sử dụng system.js, bạn có thể sử dụng System.import()trong thời gian chạy:

export class MyAppComponent {
  constructor(){
    System.import('path/to/your/module').then(refToLoadedModule => {
      refToLoadedModule.someFunction();
    }
  );
}

Nếu bạn đang sử dụng gói web, bạn có thể tận dụng tối đa sự hỗ trợ phân tách mã mạnh mẽ của nó với require.ensure:

export class MyAppComponent {
  constructor() {
     require.ensure(['path/to/your/module'], require => {
        let yourModule = require('path/to/your/module');
        yourModule.someFunction();
     }); 
  }
}

1
Có vẻ như tôi cần sử dụng bộ nạp mô-đun cụ thể trong thành phần. Chà, điều đó tốt vì Systemtương lai của loader, tôi nghĩ vậy.
CallMeLaNN

6
TypeScript Plugin for Sublime Textkhông hài lòng với Systemmã TypeScript: Cannot find name 'System'nhưng không có lỗi trong quá trình dịch mã và chạy. Cả hai Angular2Systemtập tin tập lệnh đã được thêm vào index.html. Dù sao để importcác Systemvà làm cho hạnh phúc plugin?
CallMeLaNN

1
nhưng nếu bạn không sử dụng system.js thì sao!
Murhaf Sousli

2
@drewmoore Tôi không nhớ tại sao tôi lại nói như vậy, require()/ importnên hoạt động tốt như câu trả lời của bạn bây giờ, +1
Murhaf Sousli

9
Từ những gì tôi có thể nói các tùy chọn này không hoạt động đối với các tập lệnh trên internet, chỉ dành cho các tệp cục bộ. Điều này dường như không trả lời câu hỏi ban đầu khi được hỏi.
WillyC

139

Bạn có thể sử dụng kỹ thuật sau đây để tải động các tập lệnh và thư viện JS theo yêu cầu trong dự án Angular của bạn.

script.store.ts sẽ chứa đường dẫn của tập lệnh cục bộ hoặc trên một máy chủ từ xa và một tên sẽ được sử dụng để tải tập lệnh một cách linh hoạt

 interface Scripts {
    name: string;
    src: string;
}  
export const ScriptStore: Scripts[] = [
    {name: 'filepicker', src: 'https://api.filestackapi.com/filestack.js'},
    {name: 'rangeSlider', src: '../../../assets/js/ion.rangeSlider.min.js'}
];

script.service.ts là một dịch vụ có thể tiêm sẽ xử lý việc tải tập lệnh, sao chép script.service.tsnhư nó là

import {Injectable} from "@angular/core";
import {ScriptStore} from "./script.store";

declare var document: any;

@Injectable()
export class ScriptService {

private scripts: any = {};

constructor() {
    ScriptStore.forEach((script: any) => {
        this.scripts[script.name] = {
            loaded: false,
            src: script.src
        };
    });
}

load(...scripts: string[]) {
    var promises: any[] = [];
    scripts.forEach((script) => promises.push(this.loadScript(script)));
    return Promise.all(promises);
}

loadScript(name: string) {
    return new Promise((resolve, reject) => {
        //resolve if already loaded
        if (this.scripts[name].loaded) {
            resolve({script: name, loaded: true, status: 'Already Loaded'});
        }
        else {
            //load script
            let script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = this.scripts[name].src;
            if (script.readyState) {  //IE
                script.onreadystatechange = () => {
                    if (script.readyState === "loaded" || script.readyState === "complete") {
                        script.onreadystatechange = null;
                        this.scripts[name].loaded = true;
                        resolve({script: name, loaded: true, status: 'Loaded'});
                    }
                };
            } else {  //Others
                script.onload = () => {
                    this.scripts[name].loaded = true;
                    resolve({script: name, loaded: true, status: 'Loaded'});
                };
            }
            script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'});
            document.getElementsByTagName('head')[0].appendChild(script);
        }
    });
}

}

Tiêm cái này ScriptServicebất cứ nơi nào bạn cần và tải libs js như thế này

this.script.load('filepicker', 'rangeSlider').then(data => {
    console.log('script loaded ', data);
}).catch(error => console.log(error));

7
Điều này làm việc rực rỡ. Giảm hơn 1 MB kích thước tải ban đầu - Tôi có rất nhiều thư viện!
Our_Benefactors

2
Hình như tôi đã nói quá sớm. Giải pháp này KHÔNG hoạt động trong iOS Safari.
Our_Benefactors

sau khi tải tập lệnh, hãy kiểm tra xem nó có nối với người đứng đầu của bạn không
Rahul Kumar

Có lẽ tôi không tiêm đúng, nhưng tôi nhận đượcthis.script.load is not a function
Khăn lau

Cảm ơn. Điều này hoạt động, nhưng tôi nhận được kịch bản của tôi (một hình ảnh động nền) được tải trong mọi thành phần khác. Tôi muốn nó chỉ được tải trên thành phần đầu tiên của tôi (nó là một trang đăng nhập). Tôi có thể làm gì để đạt được điều đó? Cảm ơn
Joel Azevedo

47

Điều này có thể làm việc. Mã này tự động gắn <script>thẻ vào headtệp html trên nút đã nhấp.

const url = 'http://iknow.com/this/does/not/work/either/file.js';

export class MyAppComponent {
    loadAPI: Promise<any>;

    public buttonClicked() {
        this.loadAPI = new Promise((resolve) => {
            console.log('resolving promise...');
            this.loadScript();
        });
    }

    public loadScript() {
        console.log('preparing to load...')
        let node = document.createElement('script');
        node.src = url;
        node.type = 'text/javascript';
        node.async = true;
        node.charset = 'utf-8';
        document.getElementsByTagName('head')[0].appendChild(node);
    }
}

1
Người đàn ông Thanx Làm việc cho tôi. Bây giờ bạn có thể tải nó trên tải trang bằng phương pháp ngonit. Vì vậy, nhấp vào nút là không cần thiết.
Niraj

Tôi đang sử dụng cùng một cách .. nhưng không làm việc cho tôi. Bạn có thể vui lòng giúp tôi cho cùng? this .loadJs ("đường dẫn javascriptfile"); công khai loadjs (tập tin) {let node = document.createEuity ('script'); node.src = tập tin; node.type = 'text / javascript'; node.async = true; node.charset = 'utf-8'; document.getElementsByTagName ('head') [0] .appendChild (nút); }
Mitesh Shah

Bạn đang cố gắng làm điều đó khi nhấp hoặc tải trang? Bạn có thể cho chúng tôi biết thêm về kết quả hoặc lỗi?
ng-darren

xin chào, tôi đã cố gắng thực hiện điều này và làm việc tốt nhưng new Promisekhông được giải quyết. Bạn có thể cho tôi biết tôi Promisesẽ phải nhập bất cứ điều gì?
dùng3145373

Xin chào, tôi không nhập bất cứ thứ gì đặc biệt khi tôi sử dụng Promise.
ng-darren

23

Tôi đã sửa đổi câu trả lời @rahul kumars, để nó sử dụng Observables thay thế:

import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Observer } from "rxjs/Observer";

@Injectable()
export class ScriptLoaderService {
    private scripts: ScriptModel[] = [];

    public load(script: ScriptModel): Observable<ScriptModel> {
        return new Observable<ScriptModel>((observer: Observer<ScriptModel>) => {
            var existingScript = this.scripts.find(s => s.name == script.name);

            // Complete if already loaded
            if (existingScript && existingScript.loaded) {
                observer.next(existingScript);
                observer.complete();
            }
            else {
                // Add the script
                this.scripts = [...this.scripts, script];

                // Load the script
                let scriptElement = document.createElement("script");
                scriptElement.type = "text/javascript";
                scriptElement.src = script.src;

                scriptElement.onload = () => {
                    script.loaded = true;
                    observer.next(script);
                    observer.complete();
                };

                scriptElement.onerror = (error: any) => {
                    observer.error("Couldn't load script " + script.src);
                };

                document.getElementsByTagName('body')[0].appendChild(scriptElement);
            }
        });
    }
}

export interface ScriptModel {
    name: string,
    src: string,
    loaded: boolean
}

1
Bạn quên thiết lập asyncđể true.
Will Huang

Tôi có một câu hỏi, khi chúng tôi nối thêm tập lệnh và điều hướng giữa các tuyến, giả sử tôi đã tải tập lệnh ở nhà và duyệt đến và quay trở về nhà, có cách nào để xác định lại tập lệnh hiện tại không? Có nghĩa là tôi muốn xóa cái đã tải trước đó và tải lại? Cảm ơn bạn rất nhiều
d123546

@ d123546 Có, nếu bạn muốn điều đó là có thể. Nhưng bạn phải viết một số logic loại bỏ thẻ script. Hãy xem tại đây: stackoverflow.com/questions/14708189/ Khăn
Joel

Cảm ơn Joel, nhưng có cách nào để loại bỏ các chức năng được khởi tạo bởi tập lệnh không? Hiện tại tôi đang gặp vấn đề trong dự án angular4 của mình, vì tôi đang tải tập lệnh khởi tạo thanh trượt jquery, vì vậy khi tuyến đầu tiên tải, nó sẽ hiển thị đúng, nhưng sau đó khi tôi điều hướng đến tuyến khác và quay lại tuyến của mình, tập lệnh được tải hai lần và trượt không tải nữa :( Bạn có thể tư vấn cho tôi về điều này không
d123546

1
Có một lỗi trong dòng private scripts: {ScriptModel}[] = [];. Nó nên làprivate scripts: ScriptModel[] = [];
Chris Haines

20

Một lựa chọn khác là sử dụng scriptjsgói cho vấn đề đó

cho phép bạn tải tài nguyên tập lệnh theo yêu cầu từ bất kỳ URL nào

Thí dụ

Cài đặt gói:

npm i scriptjs

định nghĩa kiểu choscriptjs :

npm install --save @types/scriptjs

Sau đó nhập $script.get()phương thức:

import { get } from 'scriptjs';

và cuối cùng tải tài nguyên tập lệnh, trong trường hợp thư viện Google Maps của chúng tôi:

export class AppComponent implements OnInit {
  ngOnInit() {
    get("https://maps.googleapis.com/maps/api/js?key=", () => {
        //Google Maps library has been loaded...
    });
  }
}

Bản giới thiệu


Cảm ơn đã chia sẻ nhưng làm thế nào có thể thêm thuộc tính bổ sung với url như async defer ?? Bạn có thể hướng dẫn tôi cách tải tập lệnh này bằng thư viện trên không? <script type = 'text / javascript' src = ' bing.com/api/maps/mapcontrol?branch=release ' async defer> </ script>
Pushkar Rathod

Vì dòng tiêu đề giống nhau nên tôi chỉ nhảy câu trả lời ở đây
Pushkar Rathod

Tuyệt vời, nhưng thay vì cài đặt npm --save @ type / scriptjs, thì nên cài đặt npm --save-dev @ type / scriptjs (hoặc chỉ npm i -D @ type / scriptjs)
Youness Houdass

18

Bạn có thể tải nhiều tập lệnh động như thế này trong component.tstệp của mình :

 loadScripts() {
    const dynamicScripts = [
     'https://platform.twitter.com/widgets.js',
     '../../../assets/js/dummyjs.min.js'
    ];
    for (let i = 0; i < dynamicScripts.length; i++) {
      const node = document.createElement('script');
      node.src = dynamicScripts[i];
      node.type = 'text/javascript';
      node.async = false;
      node.charset = 'utf-8';
      document.getElementsByTagName('head')[0].appendChild(node);
    }
  }

và gọi phương thức này bên trong hàm tạo,

constructor() {
    this.loadScripts();
}

Lưu ý: Để có nhiều tập lệnh được tải động, hãy thêm chúng vào dynamicScriptsmảng.


3
Tôi phải nói rằng, điều này có vẻ đơn giản nhưng hoạt động tốt, rất dễ thực hiện :-)
Pierre

3
Vấn đề với kiểu tiêm script này là vì Angular là một SPA, nên các script này về cơ bản vẫn nằm trên bộ đệm của trình duyệt ngay cả sau khi bạn xóa thẻ script khỏi DOM.
j4rey

1
Câu trả lời tuyệt vời! Đã cứu ngày của tôi, Nó hoạt động với Angular 6 & 7. Đã thử nghiệm!
Nadeeshan Herath

Để gửi dữ liệu đến js bên ngoài và nhận dữ liệu từ js bên ngoài, hãy gọi hàm này tại app.component.ts và sử dụng khai báo var d3Sankey: bất kỳ ở bất kỳ thành phần nào của mô-đun cấp tính năng. Nó đang hoạt động.
gnganpath

5

Tôi đã thực hiện đoạn mã này với api trình kết xuất mới

 constructor(private renderer: Renderer2){}

 addJsToElement(src: string): HTMLScriptElement {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    this.renderer.appendChild(document.body, script);
    return script;
  }

Và sau đó gọi nó như thế này

this.addJsToElement('https://widgets.skyscanner.net/widget-server/js/loader.js').onload = () => {
        console.log('SkyScanner Tag loaded');
} 

StackBlitz


4

Tôi có một cách tốt để tải động các tập lệnh! Bây giờ tôi sử dụng ng6, echarts4 (> 700Kb), ngx-echarts3 trong dự án của tôi. Khi tôi sử dụng chúng bởi tài liệu của ngx-echarts, tôi cần nhập echarts trong angular.json: "scripts": ["./ node_modules / echarts / dist / echarts.min.js"] do đó trong mô-đun đăng nhập, trang trong khi tải tập lệnh .js, đây là tập tin lớn! Tôi không muốn nó.

Vì vậy, tôi nghĩ rằng tải góc mỗi mô-đun như một tệp, tôi có thể chèn một bộ phân giải bộ định tuyến để tải trước js, sau đó bắt đầu tải mô-đun!

// PreloadScriptResolver.service.js

/**动态加载js的服务 */
@Injectable({
  providedIn: 'root'
})
export class PreloadScriptResolver implements Resolve<IPreloadScriptResult[]> {
  // Here import all dynamically js file
  private scripts: any = {
    echarts: { loaded: false, src: "assets/lib/echarts.min.js" }
  };
  constructor() { }
  load(...scripts: string[]) {
    const promises = scripts.map(script => this.loadScript(script));
    return Promise.all(promises);
  }
  loadScript(name: string): Promise<IPreloadScriptResult> {
    return new Promise((resolve, reject) => {
      if (this.scripts[name].loaded) {
        resolve({ script: name, loaded: true, status: 'Already Loaded' });
      } else {
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = this.scripts[name].src;
        script.onload = () => {
          this.scripts[name].loaded = true;
          resolve({ script: name, loaded: true, status: 'Loaded' });
        };
        script.onerror = (error: any) => reject({ script: name, loaded: false, status: 'Loaded Error:' + error.toString() });
        document.head.appendChild(script);
      }
    });
  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<IPreloadScriptResult[]> {
   return this.load(...route.routeConfig.data.preloadScripts);
  }
}

Sau đó, trong mô hình con-định tuyến.module.ts , nhập PreloadScriptResolver này:

const routes: Routes = [
  {
    path: "",
    component: DashboardComponent,
    canActivate: [AuthGuardService],
    canActivateChild: [AuthGuardService],
    resolve: {
      preloadScripts: PreloadScriptResolver
    },
    data: {
      preloadScripts: ["echarts"]  // important!
    },
    children: [.....]
}

Mã này hoạt động tốt và hứa hẹn rằng: Sau khi tệp js được tải, mô-đun bắt đầu tải! Resolver này có thể sử dụng trong nhiều bộ định tuyến


Bạn có thể vui lòng chia sẻ mã của giao diện IPreloadScriptResult không?
Mehul Bhalala

3

Một giải pháp phổ quát Angular; Tôi cần đợi một yếu tố cụ thể xuất hiện trên trang trước khi tải tập lệnh để phát video.

import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
import {isPlatformBrowser} from "@angular/common";

@Injectable({
  providedIn: 'root'
})
export class ScriptLoaderService {

  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
  ) {
  }

  load(scriptUrl: string) {
    if (isPlatformBrowser(this.platformId)) {
      let node: any = document.createElement('script');
      node.src = scriptUrl;
      node.type = 'text/javascript';
      node.async = true;
      node.charset = 'utf-8';
      document.getElementsByTagName('head')[0].appendChild(node);
    }
  }
}

1
Điều này bằng cách nào đó cảm thấy tinh ranh
Mustafa

2

Giải pháp của @ rahul-kumar phù hợp với tôi, nhưng tôi muốn gọi chức năng javascript của mình trong bản thảo

foo.myFunctions() // works in browser console, but foo can't be used in typescript file

Tôi đã sửa nó bằng cách khai báo nó trong bản thảo của mình:

import { Component } from '@angular/core';
import { ScriptService } from './script.service';
declare var foo;

Và bây giờ, tôi có thể gọi foo bất cứ nơi nào trong tập tin typecript của tôi


Nếu tôi nhập nhiều tập lệnh foo, foo1, foo2 và tôi chỉ biết trong thời gian thực hiện, làm thế nào để thực hiện khai báo một cách linh hoạt?
natrayan

2

Trong trường hợp của tôi, tôi đã tải cả tệp jscss visjstệp bằng kỹ thuật trên - hoạt động rất tốt. Tôi gọi hàm mới từngOnInit()

Lưu ý: Tôi không thể tải nó bằng cách thêm<script><link>gắn thẻ vào tệp mẫu html.

loadVisJsScript() {
  console.log('Loading visjs js/css files...');
  let script = document.createElement('script');
  script.src = "../../assets/vis/vis.min.js";
  script.type = 'text/javascript';
  script.async = true;
  script.charset = 'utf-8';
  document.getElementsByTagName('head')[0].appendChild(script);    
	
  let link = document.createElement("link");
  link.type = "stylesheet";
  link.href = "../../assets/vis/vis.min.css";
  document.getElementsByTagName('head')[0].appendChild(link);    
}


Tôi muốn tải tệp CSS từ một nguồn web bên ngoài. Hiện tại, tôi đang phải đối mặt với lỗi "Không được phép tải tài nguyên cục bộ" .. Xin đề xuất.
Karan

Tôi đã thử cách này. Mặc dù nó hoạt động tốt đối với các tệp Tập lệnh, nhưng nó không hoạt động cho Biểu định kiểu
118218

2

Xin chào, bạn có thể sử dụng Renderer2 và ElementRef chỉ với một vài dòng mã:

constructor(private readonly elementRef: ElementRef,
          private renderer: Renderer2) {
}
ngOnInit() {
 const script = this.renderer.createElement('script');
 script.src = 'http://iknow.com/this/does/not/work/either/file.js';
 script.onload = () => {
   console.log('script loaded');
   initFile();
 };
 this.renderer.appendChild(this.elementRef.nativeElement, script);
}

các onloadchức năng có thể được sử dụng để gọi các chức năng kịch bản sau khi kịch bản được nạp, điều này rất hữu ích nếu bạn cần phải làm các cuộc gọi trong ngOnInit ()


1

@ d123546 Tôi đã đối mặt với cùng một vấn đề và khiến nó hoạt động ngay bây giờ bằng cách sử dụng ngAfterContentInit (Vòng đời) trong thành phần như thế này:

import { Component, OnInit, AfterContentInit } from '@angular/core';
import { Router } from '@angular/router';
import { ScriptService } from '../../script.service';

@Component({
    selector: 'app-players-list',
    templateUrl: './players-list.component.html',
    styleUrls: ['./players-list.component.css'],
    providers: [ ScriptService ]
})
export class PlayersListComponent implements OnInit, AfterContentInit {

constructor(private router: Router, private script: ScriptService) {
}

ngOnInit() {
}

ngAfterContentInit() {
    this.script.load('filepicker', 'rangeSlider').then(data => {
    console.log('script loaded ', data);
    }).catch(error => console.log(error));
}

0

một mẫu có thể

tập tin script-loader.service.ts

import {Injectable} from '@angular/core';
import * as $ from 'jquery';

declare let document: any;

interface Script {
  src: string;
  loaded: boolean;
}

@Injectable()
export class ScriptLoaderService {
public _scripts: Script[] = [];

/**
* @deprecated
* @param tag
* @param {string} scripts
* @returns {Promise<any[]>}
*/
load(tag, ...scripts: string[]) {
scripts.forEach((src: string) => {
  if (!this._scripts[src]) {
    this._scripts[src] = {src: src, loaded: false};
  }
});

let promises: any[] = [];
scripts.forEach((src) => promises.push(this.loadScript(tag, src)));

return Promise.all(promises);
}

 /**
 * Lazy load list of scripts
 * @param tag
 * @param scripts
 * @param loadOnce
 * @returns {Promise<any[]>}
 */
loadScripts(tag, scripts, loadOnce?: boolean) {
loadOnce = loadOnce || false;

scripts.forEach((script: string) => {
  if (!this._scripts[script]) {
    this._scripts[script] = {src: script, loaded: false};
  }
});

let promises: any[] = [];
scripts.forEach(
    (script) => promises.push(this.loadScript(tag, script, loadOnce)));

return Promise.all(promises);
}

/**
 * Lazy load a single script
 * @param tag
 * @param {string} src
 * @param loadOnce
 * @returns {Promise<any>}
 */
loadScript(tag, src: string, loadOnce?: boolean) {
loadOnce = loadOnce || false;

if (!this._scripts[src]) {
  this._scripts[src] = {src: src, loaded: false};
}

return new Promise((resolve, reject) => {
  // resolve if already loaded
  if (this._scripts[src].loaded && loadOnce) {
    resolve({src: src, loaded: true});
  }
  else {
    // load script tag
    let scriptTag = $('<script/>').
        attr('type', 'text/javascript').
        attr('src', this._scripts[src].src);

    $(tag).append(scriptTag);

    this._scripts[src] = {src: src, loaded: true};
    resolve({src: src, loaded: true});
  }
 });
 }
 }

và cách sử dụng

tiêm đầu tiên

  constructor(
  private _script: ScriptLoaderService) {
  }

sau đó

ngAfterViewInit()  {
this._script.loadScripts('app-wizard-wizard-3',
['assets/demo/default/custom/crud/wizard/wizard.js']);

}

hoặc là

    this._script.loadScripts('body', [
  'assets/vendors/base/vendors.bundle.js',
  'assets/demo/default/base/scripts.bundle.js'], true).then(() => {
  Helpers.setLoading(false);
  this.handleFormSwitch();
  this.handleSignInFormSubmit();
  this.handleSignUpFormSubmit();
  this.handleForgetPasswordFormSubmit();
});

0
import { Injectable } from '@angular/core';
import * as $ from 'jquery';

interface Script {
    src: string;
    loaded: boolean;
}

@Injectable()
export class ScriptLoaderService {
    public _scripts: Script[] = [];

    /**
     * @deprecated
     * @param tag
     * @param {string} scripts
     * @returns {Promise<any[]>}
     */
    load(tag, ...scripts: string[]) {
        scripts.forEach((src: string) => {
            if (!this._scripts[src]) {
                this._scripts[src] = { src: src, loaded: false };
            }
        });

        const promises: any[] = [];
        scripts.forEach(src => promises.push(this.loadScript(tag, src)));

        return Promise.all(promises);
    }

    /**
     * Lazy load list of scripts
     * @param tag
     * @param scripts
     * @param loadOnce
     * @returns {Promise<any[]>}
     */
    loadScripts(tag, scripts, loadOnce?: boolean) {
        debugger;
        loadOnce = loadOnce || false;

        scripts.forEach((script: string) => {
            if (!this._scripts[script]) {
                this._scripts[script] = { src: script, loaded: false };
            }
        });

        const promises: any[] = [];
        scripts.forEach(script => promises.push(this.loadScript(tag, script, loadOnce)));

        return Promise.all(promises);
    }

    /**
     * Lazy load a single script
     * @param tag
     * @param {string} src
     * @param loadOnce
     * @returns {Promise<any>}
     */
    loadScript(tag, src: string, loadOnce?: boolean) {
        debugger;
        loadOnce = loadOnce || false;

        if (!this._scripts[src]) {
            this._scripts[src] = { src: src, loaded: false };
        }

        return new Promise((resolve, _reject) => {
            // resolve if already loaded
            if (this._scripts[src].loaded && loadOnce) {
                resolve({ src: src, loaded: true });
            } else {
                // load script tag
                const scriptTag = $('<script/>')
                    .attr('type', 'text/javascript')
                    .attr('src', this._scripts[src].src);

                $(tag).append(scriptTag);

                this._scripts[src] = { src: src, loaded: true };
                resolve({ src: src, loaded: true });
            }
        });
    }

    reloadOnSessionChange() {
        window.addEventListener('storage', function(data) {
            if (data['key'] === 'token' && data['oldValue'] == null && data['newValue']) {
                document.location.reload();
            }
        });
    }
}
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.