如何避免在加载外部 JS 文件之前丢失对它的调用
我的问题是,多个网站将包含我的 JS 文件,并且在调用类似这样的内容时:
<script src="..."></script>
hello.say("yay");
将会出现竞争问题,因此有时可能会出现这种情况,有时则不会。我知道我可以通过将每个函数放入 window.onload
中来轻松解决这个问题,但这并不干净,因为我已经看到其他网站神奇地解决了这个问题,例如谷歌分析:
.. Calling google analytics JS..
<script type="text/javascript">
try{
var pageTracker = _gat._getTracker("UA-xxxxxx-x"); <-- this an object !
pageTracker._trackPageview();
} catch(err) {}
</script>
如何做到这一点?
My issue is that multiple websites are going to include my JS file and when calling something like this:
<script src="..."></script>
hello.say("yay");
there going to be a race issue so sometimes it could make it sometimes not. i know that i can solve that easily by putting every function in a window.onload
but that wouldn't be clean as i've seen other websites magically solve that like google analytics:
.. Calling google analytics JS..
<script type="text/javascript">
try{
var pageTracker = _gat._getTracker("UA-xxxxxx-x"); <-- this an object !
pageTracker._trackPageview();
} catch(err) {}
</script>
How to do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Google Analytics 使用的技巧是只能用鸭子类型语言完成的完美示例。如果 GA 脚本尚未加载,则主对象是一个数组,但如果加载了,它的行为就会改变。让我们看看我能否解释一下。
我从 stackoverflow 的源代码中提取了这篇文章:
它看起来像一个数组,其中有一些值被推送到其中。事实上,如果
_gaq
是 falsy 当此代码运行时(就像尚未运行其他分析 JavaScript 一样),它作为一个数组。然后,当主分析脚本(包含在页面上任何位置的脚本标签中)加载时,它会检查该数组并根据该数组的内容执行某些任务。因此,如果这种情况以相反的顺序发生(首先加载主脚本,然后加载上面的代码片段),则主脚本将
_gaq
设置为具有推送方法的对象,该对象可以执行 google 希望它执行的任何操作。稍后,当上面的代码运行时,_gaq.push
不只是将值添加到数组中;而是将值添加到数组中。它实际上执行任意代码(并且根本不推送到数组)。因此,无论哪个脚本先运行,当两个脚本都完成时,最终结果将是相同的。
Google Analytics uses a trick that's a perfect example of something that can only be done in duck typed languages. The main object is an array if the GA-script hasn't loaded, but if it has it changes behaviour. Let's see if I can explain it.
I pulled this piece from the source here at stackoverflow:
It looks like an array with some values being pushed to it. In fact, if
_gaq
is falsy when this code is run (as it is if no other analytics-JavaScript has run yet), it as an array. Then, when the main analytics script (included with a script-tag anywhere on the page) loads it examines this array and performs some task based on the contents of the array.So, if this happens in opposite order (the main script is loaded first, and then the snippet above) the main script set
_gaq
to an object with a push-method that does whatever google wants it to do. Later, when the code above runs,_gaq.push
doesn't just add values to an array; it actually executes arbitrary code (and doesn't push to an array at all).Hence, regardless of which script runs first, the end result will be the same when both have finished.
如果您将文件包含在 html 页面的标头部分中,则该文件将在页面中运行任何其他 javascript 之前加载。
UPD:另外,我认为甚至 thml 文本中包含的文件也会在处理其余 javascript 之前下载。您确定这首先是您的问题吗?
If you include your file in the header part of the html page, it will be loaded before any other javascript in the page is run.
UPD: Also, I think even files included in the text of thml are downloaded before the processing of the rest of javascripts. Are you sure that is your problem in the first place?
您需要延迟执行任何依赖于外部 javascript 的 javascript 代码,直到页面完全加载之后,您可以通过将执行附加到 window.onload 事件来做到这一点。
但这的缺点是仅适用于一个函数,并且会覆盖最初附加到该事件的任何函数。您可能需要阅读 Simon Wilson 的帖子和评论,以获取有关如何处理这种情况的解决方案。
http://simonwillison.net/2004/May/26/addLoadEvent/
You will need to delay the execution of any javascript code that depends on the external javascript until after the page has been fully loaded and you can do that by attaching the execution to the window.onload event.
But this has the disadvantage of only working for one function and will override any functions that have been initially attached to that event. You would want to read Simon Wilson's post and the comments for solutions on how to handle this situation.
http://simonwillison.net/2004/May/26/addLoadEvent/
我有点不确定你认为这里的种族问题是什么。
浏览器总是*按照它们看到的顺序执行脚本标签。如果这不是真的,那么互联网的很大一部分将会崩溃——以及几乎所有现有的常见 JavaScript 库。
因此,只要用户在文档中比调用其 API 时更早加载您的脚本,就应该没有问题。我能想到的唯一潜在的例外是,如果您的脚本的初始化依赖于异步逻辑,在这种情况下,您应该考虑提供自己的标准回调机制,供用户编写代码。
如果用户可能会在之后加载您的脚本他们使用其 API 的点,那么雅各布在他的回答中提到的技巧就会起作用。但我什至不确定你的目标是达到那种复杂程度。
*编辑:我应该注意到,说实话,有特定的例外情况,但只要您只是处理
标签中的标准非延迟使用即可。 HTML 文档。
I'm a bit unsure as to what you think the race issue is here.
Browsers always* execute script tags in the order they see them. If this were not true, a good portion of the internet would break - as well as pretty much every common JavaScript library in existence.
So, as long as users load your script earlier in the document than when they call its APIs, you should have no problem. The only potential exception to this I can think of is if your script's initialization relies on asynchronous logic, in which case you should think about providing a standard callback mechanism of your own for users to write their code in.
If users might load your script AFTER the point they use its APIs, then the trick Jakob alludes to in his answer would work. But I'm not even sure you're aiming for that level of complexity.
*edit: I should note, to be perfectly honest, there are specific exceptions to this, but not so long as you're simply dealing with standard non-deferred usage of
<script>
tags within an HTML document.