草庐IT

javascript - 动态添加的脚本标签的加载顺序

coder 2023-08-03 原文

我有一个 typescript 应用程序,它动态添加指向 JS 文件的脚本标签。由于一些限制,我不能在 html 文件中静态定义这些脚本标签,所以我通过 typescript 动态添加它们,如下所示:

for (let src of jsFiles) {
  let sTag = document.createElement('script');
  sTag.type = 'text/javascript';
  sTag.src = src;
  sTag.defer = true;
  document.body.appendChild(script);
}

现在,我注意到,当我动态添加脚本标签时,它们似乎不能保证它们的加载顺序。不幸的是,jsFiles 数组具有相互依赖的脚本。因此,数组中的第二个脚本只能在第一个完全加载后才能加载。第二个脚本引用第一个脚本中定义的函数。有没有一种方法可以指定动态添加脚本时脚本的排序和执行顺序(类似于在 html 文件中静态定义脚本标签时的排序方式)?

附言我想避免使用 onload 回调来解决这个问题,因为我注意到我的应用程序性能下降。我的第二个脚本文件非常大,我假设它导致了性能下降。

最佳答案

我可以提及一些替代方案来克服该要求:

  1. 使用库注入(inject)依赖项(AMD 或 CommonJS 模块)
    只需使用modules 。 ES2015:import/export,或 CommonJS:require()
  2. 以编程方式创建 script 标记并设置回调 onload 以便在异步加载脚本时使用react。默认设置属性 async = true
  3. 如果您被允许修改要注入(inject)的脚本,则在脚本末尾添加一行带有objectarray 的跟踪脚本已经加载。
  4. 您可以将脚本作为文本 (XMLHttpRequest) 获取,然后按要求的顺序使用脚本构建一个 string,最后通过以下方式执行文本脚本eval()
  5. 还有一个不太推荐但经常使用的选项,设置一个 setInterval 来检查脚本是否已经执行。

我建议选择第一个选项。但出于学术目的,我将说明第二种选择:

Create the script tag programmatically and set the callback onload in order to react when the script has been loaded asynchronously.

我想推荐一本关于脚本加载器的读物: Deep dive into the murky waters of script loading ,值得花半个小时!

下面的例子是一个管理脚本注入(inject)的小模块,这是它背后的基本思想:

let _scriptsToLoad = [
  'path/to/script1.js',
  'path/to/script2.js',
  'path/to/script3.js'
];

function createScriptElement() {
  // gets the first script in the list
  let script = _scriptsToLoad.shift();
  // all scripts were loaded
  if (!script) return;
  let js = document.createElement('script');
  js.type = 'text/javascript';
  js.src = script;
  js.onload = onScriptLoaded;
  let s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(js, s);
}

function onScriptLoaded(event) {
  // loads the next script
  createScriptElement();
};

在此plunker中,您可以按特定顺序异步测试脚本注入(inject):

主要想法是创建一个 API,允许您通过公开以下方法与要注入(inject)的脚本进行交互:

  • addScript:接收要加载的每个脚本的 URL 或 URL 列表。
  • load:运行任务以按指定顺序加载脚本。
  • reset:清除脚本数组,或者取消脚本加载。
  • afterLoad:每个脚本加载完成后执行的回调。
  • onComplete:所有脚本加载完成后执行的回调。

我喜欢Fluent Interface方法链 技术,所以我以这种方式构建了模块:

  scriptsLoader
    .reset()
    .addScript("script1.js")
    .addScript(["script2.js", "script3.js"])
    .afterLoad((src) => console.warn("> loaded from jsuLoader:", src))
    .onComplete(() => console.info("* ALL SCRIPTS LOADED *"))
    .load();

在上面的代码中,我们首先加载了"script1.js"文件,并执行了afterLoad()回调,接下来,对做同样的事情“script2.js”“script3.js” 并且在加载所有脚本后,执行 onComplete() 回调。

关于javascript - 动态添加的脚本标签的加载顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38839650/

有关javascript - 动态添加的脚本标签的加载顺序的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  4. ruby - 在院子里用@param 标签警告 - 2

    我试图使用yard记录一些Ruby代码,尽管我所做的正是所描述的here或here#@param[Integer]thenumberoftrials(>=0)#@param[Float]successprobabilityineachtrialdefinitialize(n,p)#initialize...end虽然我仍然得到这个奇怪的错误@paramtaghasunknownparametername:the@paramtaghasunknownparametername:success然后生成的html看起来很奇怪。我称yard为:$yarddoc-mmarkdown我做错了什么?

  5. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  6. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  7. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  8. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  9. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  10. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

随机推荐