关于javascript:脚本文件执行内联脚本与CDN或外部域在HTML注入

Script File Executing After Inline Script With CDN or External Domain On HTML injection

我在一个已经加载的DOM中遇到了HTML注入问题,在该DOM中,脚本文件下载后将加载内联javascript。据我所知,这不应该是异步的,内联脚本应该在脚本文件之后执行。如果域名与调用页相同,但使用cdn或甚至子域也会做同样的事情,那么这就可以工作。我是否需要做些什么来修改我称之为这些的方式?我发誓这以前是有效的,因为我有一个多星期的内容交付网络,但也许我从来没有发现这个问题。

慰问

1
2
3
4
Loading Inline Script
VM1400:3 Uncaught TypeError: Cannot read property 'init' of undefined(anonymous function)
app.members.event.js?v=204&_=1453644424985:5 Loading Script File
app.members.event.js?v=204&_=1453644424985:71 Finished Script File

JavaScript

1
2
3
4
5
<script type="text/javascript" src="https://test.azureedge.net/Areas/Directors/scripts/app.members.event.js?v=204">
<script type="text/javascript">
console.log('Loading Inline Script');
    app.viewModel.members.event.init();
console.log('Finished Inline Script');


一种方法是使用jquery的getscript()函数。

但最好使用本机JavaScript加载脚本文件,然后运行内联脚本。

也许我对这个问题理解不清楚。

编辑:这是HTML5规范中关于脚本元素的引用。

If the element has a src content attribute, run these substeps:

Let src be the value of the element's src attribute.

If src is the empty string, queue a task to fire a simple event named
error at the element, and abort these steps.

Resolve src relative to the element.

If the previous step failed, queue a task to fire a simple event named
error at the element, and abort these steps.

Do a potentially CORS-enabled fetch of the resulting absolute URL,
with the mode being the current state of the element's crossorigin
content attribute, the origin being the origin of the script element's
Document, and the default origin behaviour set to taint.

The resource obtained in this fashion can be either CORS-same-origin
or CORS-cross-origin. This only affects how error reporting happens.

For performance reasons, user agents may start fetching the script (as
defined above) as soon as the src attribute is set, instead, in the
hope that the element will be inserted into the document (and that the
crossorigin attribute won't change value in the meantime). Either way,
once the element is inserted into the document, the load must have
started as described in this step. If the UA performs such
prefetching, but the element is never inserted in the document, or the
src attribute is dynamically changed, or the crossorigin attribute is
dynamically changed, then the user agent will not execute the script
so obtained, and the fetching process will have been effectively
wasted.

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

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.

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.

If the element does not have a src attribute, and the element has been
flagged as"parser-inserted", and either the parser that created the
script is an XML parser or it's an HTML parser whose script nesting
level is not greater than one, 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.

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: 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.

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. Fetching an external
script must delay the load event of the element's document until the
task that is queued by the networking task source once the resource
has been fetched (defined above) has been run.

因此,我认为您的"外部"文件是在内联脚本块之后加载的。因此,我将使用jquery中的"getscript()"函数确保在内联脚本块之前加载脚本。


1
2
3
function onloadCallback(){
    app.viewModel.members.event.init();
}


使用此:

1
2
3
4
<script type="text/javascript" src="https://test.azureedge.net/Areas/Directors/scripts/app.members.event.js?v=204&onload=onloadCallback"></script

<script type="text/javascript">function onloadCallback(){
app.viewModel.members.event.init();}

这是注射场景中常见的问题。它发生的原因是脚本可用性的可变延迟,以及不同浏览器上的并行和不同实现。好的。

根据源代码是否可编辑以及脚本文件之间是否存在2个以上的依赖关系,有3个选项。好的。

选项1。在脚本标记中使用defer属性好的。

如果两个脚本都是远程的(即,不是内联的),则可以使用此选项。好的。

"defer"向浏览器指示在分析文档(从MDN引用)之后必须执行脚本。这仅适用于具有"src"属性的远程(而不是内联)脚本。好的。

https://html.spec.whatwg.org/multipage/scripting.html attr script defer好的。

你可以像下面那样使用它。好的。

主要浏览器支持延迟,我在Chrome、Firefox、Tizen的Webkit和Safari上进行了验证:好的。

https://developer.mozilla.org/en/docs/web/html/element/script浏览器兼容性好的。

为提供上述情况的具体示例,请参阅下文。请注意,以下内容已经在Firefox、Chrome、IE11、iPhone上的Safari和Tizen上的WebKit上得到验证。好的。

案例1:好的。

许多javascript文件-全部独立:好的。

如果没有依赖关系,"defer"属性允许快速加载HTML。该脚本在下载后接管,没有问题(假设onload等得到重视)。好的。

案例2:好的。

两个javascript文件test1.js和test2.js-一个依赖于另一个:好的。

如果test2.js依赖于test1.js的加载,那么test2.js"only"的脚本标记应该具有defer属性。好的。

此用法显示在好的。

http://www.gpupowered.org/loadtest/2_defer.html好的。

不正确的用法如所示好的。

http://www.gpupowered.org/loadtest/no_defer.html(两个脚本都没有defer标记-失败)http://www.gpupowered.org/loadtest/all_defer.html(两个脚本都有defer标记-这也会失败)好的。

不起作用的异步用法位于,好的。

http://gpupowered.org/loadtest/2_async.html(失败)好的。

"延期"在哪里不能满足需求?好的。

如果功能被拆分为多个JS文件(例如n),并且在"n"文件开始处理某些变量之前需要下载所有"n-1",即使"defer"属性可能出现在所有脚本源标记上,它也会变得不相关,因为接收它们的顺序是不确定的。好的。

关于延迟和延迟加载的各种选项的更多背景(不包括多延迟情况)http://www.html5rocks.com/en/tutorials/speed/script-loading/好的。

https://developer.mozilla.org/en/docs/web/html/element/script好的。

选项2:使用状态变量好的。

如果可以向两个javascript源文件中添加一些额外的状态变量,则可以使用此选项。好的。

该方法依赖于依赖JS文件中的一个命名变量,以及使用依赖文件的JS文件中的一个命名函数。如果在用户文件尝试访问其功能时未加载依赖文件,则该文件将退出,并在实际加载时被调用。好的。

这在下面的HTML文件中演示。好的。

http://gpupowered.org/loadtest/variable.html(工作正常)好的。

如果需要重复加载(即加载多个同名文件等),则此选项不起作用。好的。

选项3:本机脚本加载程序好的。

在这种情况下,有多个javascript文件彼此之间具有依赖关系。好的。

对于这种情况,没有使用defer、async或其他规范提供的标记的解决方案。对于我在gpupowered.org的远程实验室中的用例,我必须使用xmlhttpRequest实现我自己的本地脚本加载器,其源代码在下面的链接中提供。它使用工作线程作为我拥有的一些相当大的纹理。回调函数可以根据应用需要实现依赖逻辑。例如,保持所有加载脚本的计数,然后触发完全执行等。好的。

https://github.com/prabindh/gpupowered.gl/blob/master/worker/worker_object_loader.js好的。

jquery脚本加载器也使用HTTP请求,不过我还没有检查它是否使用Worker进行加载。https://api.jquery.com/jquery.getscript/好的。好啊。


我有两种理论:

  • 可能是外部脚本中有某种东西延迟了app.viewModel.members对象的创建(超时或需要一段时间才能完成的事件处理程序)。通过在内联脚本(f.i.5000+ms)中设置长时间超时,然后检查models对象是否存在,可以很容易地测试这一点。

  • 当加载同一个源脚本时,会发生一些奇怪的事情。

  • 在这种情况下,您可以尝试通过执行以下操作来延迟内联脚本的执行:

    1
    2
    3
    4
    <script type="text/javascript">
    document.addEventListener("DOMContentLoaded", function(event) {
        app.viewModel.members.event.init();
    });

    或者将内联代码放到外部.js文件中,并使用"deferred"标志调用它:

    1
    2
    <script type="text/javascript" src="https://test.azureedge.net/Areas/Directors/scripts/app.members.event.js?v=204">
    <script type="text/javascript" src="{link-to-external-js-file}" defer>