加载和执行脚本的顺序 [英] load and execute order of scripts

查看:32
本文介绍了加载和执行脚本的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 html 页面中包含 JavaScript 的方法有很多种.我知道以下选项:

There are so many different ways to include JavaScript in a html page. I know about the following options:

  • 内联代码或从外部 URI 加载
  • 包含在 <head> 或 <body> 标签中 [1,2]
  • 没有,deferasync 属性(仅限外部脚本)
  • 包含在静态源中或由其他脚本动态添加(在不同的解析状态,使用不同的方法)
  • inline code or loaded from external URI
  • included in <head> or <body> tag [1,2]
  • having none, defer or async attribute (only external scripts)
  • included in static source or added dynamically by other scripts (at different parse states, with different methods)

不计算来自硬盘的浏览器脚本、javascript:URI 和 onEvent-属性 [3],已经有 16 种替代方法可以让 JS 执行,我确定我忘记了一些东西.

Not counting browserscripts from the harddisk, javascript:URIs and onEvent-attributes [3], there are already 16 alternatives to get JS executed and I'm sure I forgot something.

我不太关心快速(并行)加载,我更关心执行顺序(这可能取决于加载顺序和 文档顺序).是否有一个很好的(跨浏览器)参考,可以真正涵盖所有情况?http://www.websiteoptimization.com/speed/tweak/defer/ 仅优惠其中有 6 个,主要测试旧浏览器.

I'm not so concerned with fast (parallel) loading, I'm more curious about the execution order (which may depend on loading order and document order). Is there a good (cross-browser) reference that covers really all cases? E.g. http://www.websiteoptimization.com/speed/tweak/defer/ only deals with 6 of them, and tests mostly old browsers.

我担心没有,这是我的具体问题:我有一些(外部)头脚本用于初始化和脚本加载.然后我在正文的末尾有两个静态的内联脚本.第一个让脚本加载器动态地将另一个脚本元素(引用外部 js)附加到正文中.第二个静态内联脚本想要使用来自添加的外部脚本的 js.它可以依赖另一个已被执行吗(为什么:-)?

As I fear there's not, here is my specific question: I've got some (external) head scripts for initialisation and script loading. Then I've got two static, inline scripts in the end of the body. The first one lets the script loader dynamically append another script element (referencing external js) to the body. The second of the static, inline scripts wants to use js from the added, external script. Can it rely on the other having been executed (and why :-)?

推荐答案

如果您不是动态加载脚本或将它们标记为 deferasync,则脚本是按照页面中遇到的顺序加载.无论是外部脚本还是内联脚本都无关紧要 - 它们按照在页面中遇到的顺序执行.在外部脚本之后的内联脚本被保留,直到它们之前的所有外部脚本都加载并运行.

If you aren't dynamically loading scripts or marking them as defer or async, then scripts are loaded in the order encountered in the page. It doesn't matter whether it's an external script or an inline script - they are executed in the order they are encountered in the page. Inline scripts that come after external scripts are held until all external scripts that came before them have loaded and run.

异步脚本(无论它们如何指定为异步)以不可预测的顺序加载和运行.浏览器并行加载它们,并且可以按照它想要的任何顺序自由地运行它们.

Async scripts (regardless of how they are specified as async) load and run in an unpredictable order. The browser loads them in parallel and it is free to run them in whatever order it wants.

多个异步事物之间没有可预测的顺序.如果需要可预测的顺序,则必须通过从异步脚本注册加载通知并在加载适当的内容时手动对 javascript 调用进行排序来进行编码.

There is no predictable order among multiple async things. If one needed a predictable order, then it would have to be coded in by registering for load notifications from the async scripts and manually sequencing javascript calls when the appropriate things are loaded.

当动态插入脚本标签时,执行顺序的行为将取决于浏览器.您可以在这篇参考文章中了解 Firefox 的行为.简而言之,除非另外设置了脚本标签,否则较新版本的 Firefox 默认将动态添加的脚本标签设为异步.

When a script tag is inserted dynamically, how the execution order behaves will depend upon the browser. You can see how Firefox behaves in this reference article. In a nutshell, the newer versions of Firefox default a dynamically added script tag to async unless the script tag has been set otherwise.

带有 async 的脚本标记可能会在加载后立即运行.事实上,浏览器可能会暂停解析器正在执行的任何其他操作并运行该脚本.所以,它几乎可以在任何时候运行.如果脚本被缓存,它可能几乎立即运行.如果脚本需要一段时间加载,它可能会在解析器完成后运行.async 要记住的一件事是它可以随时运行,而且时间是不可预测的.

A script tag with async may be run as soon as it is loaded. In fact, the browser may pause the parser from whatever else it was doing and run that script. So, it really can run at almost any time. If the script was cached, it might run almost immediately. If the script takes awhile to load, it might run after the parser is done. The one thing to remember with async is that it can run anytime and that time is not predictable.

带有 defer 的脚本标签会等待整个解析器完成,然后按照遇到的顺序运行所有标有 defer 的脚本.这允许您将几个相互依赖的脚本标记为 defer.它们都将被推迟到文档解析器完成之后,但它们将按照遇到的顺序执行,并保留它们的依赖关系.我认为 defer 就像脚本被放入解析器完成后将被处理的队列中.从技术上讲,浏览器可能随时在后台下载脚本,但在解析器完成页面解析并解析和运行任何未标记 defer 的内联脚本之前,它们不会执行或阻止解析器async.

A script tag with defer waits until the entire parser is done and then runs all scripts marked with defer in the order they were encountered. This allows you to mark several scripts that depend upon one another as defer. They will all get postponed until after the document parser is done, but they will execute in the order they were encountered preserving their dependencies. I think of defer like the scripts are dropped into a queue that will be processed after the parser is done. Technically, the browser may be downloading the scripts in the background at any time, but they won't execute or block the parser until after the parser is done parsing the page and parsing and running any inline scripts that are not marked defer or async.

这是那篇文章的引述:

插入脚本的脚本在 IE 和 WebKit 中异步执行,但是在 Opera 和 4.0 之前的 Firefox 中同步.

script-inserted scripts execute asynchronously in IE and WebKit, but synchronously in Opera and pre-4.0 Firefox.

HTML5 规范的相关部分(适用于较新的兼容浏览器)是 这里.那里有很多关于异步行为的文章.显然,此规范不适用于您可能需要测试以确定其行为的旧版浏览器(或不符合标准的浏览器).

The relevant part of the HTML5 spec (for newer compliant browsers) is here. There is a lot written in there about async behavior. Obviously, this spec doesn't apply to older browsers (or mal-conforming browsers) whose behavior you would probably have to test to determine.

引用 HTML5 规范:

A quote from the HTML5 spec:

然后,描述情况的以下选项中的第一个必须遵守:

Then, the first of the following options that describes the situation must be followed:

如果元素有 src 属性,并且元素有 defer属性,并且该元素已被标记为解析器插入",并且该元素没有 async 属性必须添加元素到将在文档中执行的脚本列表的末尾已完成与解析器的 Document 关联的解析创建了元素.

If the element has a src attribute, and the element has a defer attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute The element must be added to the end of the list of scripts that will execute when the document has finished parsing associated with the Document of the parser that created the element.

联网任务源一次放入任务队列的任务获取算法已完成必须设置元素的准备好被解析器执行"标志.解析器将处理执行脚本.

The task that the networking task source places on the task queue once the fetching algorithm has completed must set the element's "ready to be parser-executed" flag. The parser will handle executing the script.

如果元素有 src 属性,并且元素已经被标记作为解析器插入",并且该元素没有 async 属性该元素是 Document 的待处理的解析块脚本创建元素的解析器.(只能有一个这样的一次为每个文档编写脚本.)

If the element has a src attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute The element is the pending parsing-blocking script of the Document of the parser that created the element. (There can only be one such script per Document at a time.)

联网任务源一次放入任务队列的任务获取算法已完成必须设置元素的准备好被解析器执行"标志.解析器将处理执行脚本.

The task that the networking task source places on the task queue once the fetching algorithm has completed must set the element's "ready to be parser-executed" flag. The parser will handle executing the script.

如果元素没有 src 属性,并且元素已经被标记为解析器插入",以及 HTML 解析器的文档或创建脚本元素的 XML 解析器有一个样式表阻塞脚本 元素是挂起的解析阻塞脚本创建元素的解析器的文档.(只有一次为每个文档一个这样的脚本.)

If the element does not have a src attribute, and the element has been flagged as "parser-inserted", and the Document of the HTML parser or XML parser that created the script element has a style sheet that is blocking scripts The element is the pending parsing-blocking script of the Document of the parser that created the element. (There can only be one such script per Document at a time.)

设置元素的准备好被解析器执行"标志.解析器将处理执行脚本.

Set the element's "ready to be parser-executed" flag. The parser will handle executing the script.

如果元素有 src 属性,没有 async 属性,并且没有设置force-async"标志 必须添加元素到将尽快按顺序执行的脚本列表的末尾尽可能与脚本元素的 Document 相关联准备脚本算法开始的时间.

If the element has a src attribute, does not have an async attribute, and does not have the "force-async" flag set The element must be added to the end of the list of scripts that will execute in order as soon as possible associated with the Document of the script element at the time the prepare a script algorithm started.

联网任务源一次放入任务队列的任务获取算法完成后必须运行以下步骤:

The task that the networking task source places on the task queue once the fetching algorithm has completed must run the following steps:

如果该元素现在不是脚本列表中的第一个元素将尽快按添加到的顺序执行 然后将元素标记为就绪但不中止这些步骤正在执行脚本.

If the element is not now the first element in the list of scripts that will execute in order as soon as possible to which it was added above, then mark the element as ready but abort these steps without executing the script yet.

Execution:执行第一个脚本对应的脚本块此脚本列表中的元素将按顺序执行可能.

Execution: Execute the script block corresponding to the first script element in this list of scripts that will execute in order as soon as possible.

从将要执行的脚本列表中删除第一个元素以便尽快.

Remove the first element from this list of scripts that will execute in order as soon as possible.

如果这个脚本列表会尽快按顺序执行仍然不为空,第一个条目已经被标记为准备好,然后跳回标记为执行的步骤.

If this list of scripts that will execute in order as soon as possible is still not empty and the first entry has already been marked as ready, then jump back to the step labeled execution.

如果元素有 src 属性 元素必须添加到将尽快执行 Document 的一组脚本准备脚本算法时的脚本元素开始了.

If the element has a src attribute The element must be added to the set of scripts that will execute as soon as possible of the Document of the script element at the time the prepare a script algorithm started.

联网任务源一次放入任务队列的任务获取算法已完成必须执行脚本块和然后从将执行为的脚本集中删除元素尽快.

The task that the networking task source places on the task queue once the fetching algorithm has completed must execute the script block and then remove the element from the set of scripts that will execute as soon as possible.

否则 用户代理必须立即执行脚本块,即使其他脚本已经在执行.

Otherwise The user agent must immediately execute the script block, even if other scripts are already executing.

<小时>

Javascript 模块脚本怎么样,type="module"?

Javascript 现在支持模块加载,语法如下:

Javascript now has support for module loading with syntax like this:

<script type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Modules are pretty cool.');
</script>

或者,使用 src 属性:

<script type="module" src="http://somedomain.com/somescript.mjs">
</script>

所有带有 type="module" 的脚本都会自动赋予 defer 属性.这会与页面的其他加载并行(如果不是内联)下载它们,然后按顺序运行它们,但在解析器完成之后.

All scripts with type="module" are automatically given the defer attribute. This downloads them in parallel (if not inline) with other loading of the page and then runs them in order, but after the parser is done.

模块脚本也可以被赋予 async 属性,它会尽快运行内联模块脚本,而不是等到解析器完成并且不等待运行 async 相对于其他脚本的任何特定顺序的脚本.

Module scripts can also be given the async attribute which will run inline module scripts as soon as possible, not waiting until the parser is done and not waiting to run the async script in any particular order relative to other scripts.

有一个非常有用的时间线图表,显示了不同脚本组合的获取和执行,包括本文中的模块脚本:Javascript 模块加载.

There's a pretty useful timeline chart that shows fetch and execution of different combinations of scripts, including module scripts here in this article: Javascript Module Loading.

这篇关于加载和执行脚本的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆