Ah, asynchronous JavaScripts. Love 'em, hate 'em, but you gotta use them!
嗯,异步JavaScript。 爱他们,恨他们,但您必须使用它们!
I have quite a few posts here on this blog about this stuff. Starting with something I considered an interesting hack to emulate PHP's require(). This was posted in 2005. (2005! That's ancient. That's only a year after gmail was introduced, and you know gmail has been around, like, always). Then there was this and this and this and this. These days dynamic SCRIPT tags are something common, mainly because of their non-blocking behavior that helps performance. This is all good.
我在此博客上有很多与此相关的文章。 与开始的东西我认为是一个有趣的黑客模仿PHP的需要()。 这是在2005年发布的。(2005年!那是很古老的。在gmail推出仅一年之后,您就知道gmail一直存在,就像一直一样)。 然后就是这个和这个,这个和这个。 如今,动态SCRIPT标签很常见,主要是因为它们的非阻塞行为有助于提高性能。 一切都很好。
I wanted to highlight the part where you load a script file and then execute a function once the file is done loading. A common, but kinda wrong pattern I've posted back at the time, and tweaked a little since, is like so:
我想突出显示您加载脚本文件的部分,然后在文件加载完成后执行功能。 我当时发布的一种常见但有点错误的模式,此后进行了一些调整,如下所示:
var first_html" title=js>js = document.getElementsByTagName('script')[0];
var html" title=js>js = document.createElement('script');
html" title=js>js.src = file;
// normal browsers
html" title=js>js.onload = function () {
alert('loaded!!');
};
// IE
html" title=js>js.onreadystatechange = function () {
if (html" title=js>js.readyState in {complete: 1, loaded: 1}) {
alert('loaded!!');
}
};
first_html" title=js>js.parentNode.insertBefore(html" title=js>js, first_html" title=js>js);
Back at the time (2006) this was fine. The problem is now that since version 9, IE supports onload
handler in script elements. But it also supports onreadystatechange
for backwards compatibility.
追溯到当时(2006年),情况很好。 现在的问题是,从版本9开始,IE在脚本元素中支持onload
处理程序。 但是它也支持onreadystatechange
以便向后兼容。
In other words in IE9+ your callbacks will be executed twice. Not good.
换句话说,在IE9 +中,您的回调将执行两次。 不好。
单次回调 (Single callback)
There are various ways to deal with this situation.
有多种方法可以处理这种情况。
1. You can delete the onload
callback in readystatechange
, beacuse readystatechange
is called first.
1.您可以在readystatechange
删除onload
回调,因为首先要调用readystatechange
。
html" title=js>js.onreadystatechange = function () {
if (html" title=js>js.readyState in {complete: 1, loaded: 1}) {
callback();
html" title=js>js.onload = null;
}
};
2. You can use a single assignment to both
2.您可以对两者使用单个分配
html" title=js>js.onload = html" title=js>js.onreadystatechange = function () {
// stuff...
html" title=js>js.onload = html" title=js>js.onreadystatechange = null;
};
The problem with both of these is that readystatechange
is involved even in browsers that are modern (IE9+) and support onload
. Feels a bit ugh.
两者的问题在于,即使在现代(IE9 +)和支持onload
浏览器中,也都需要readystatechange
。 感觉有点丑。
3. You can sniff onload
support
3.您可以嗅探onload
支持
if (typeof html" title=js>js.onload !== 'undefined') {
// good stuff..
} else {
// onreadystatechange jazz
}
This works because old IEs will not have any onload
property (hence undefined
) while supporting browsers will have this property initially set to null
.
之所以可行,是因为旧的IE将没有任何onload
属性(因此undefined
),而支持的浏览器会将此属性最初设置为null
。
Hmm, making a distinction between two falsy values null
and undefined
seems a little fragile. The next developer will come and say: "meh, what's with the typeof
verbosity, let's just say if (html" title=js>js.onload)
"... And the whole thing will fail.
嗯,区分两个虚假值null
和undefined
似乎有些脆弱。 接下来开发商会说:“咩,用什么typeof
冗长,让我们只说if (html" title=js>js.onload)
” ......而整个事情会失败。
4. (And this is my preferred method) is to sniff support using addEventListener
.
4.(这是我的首选方法)是使用addEventListener
嗅探支持。
It just happens so that IE9, which supports onload
, is also the first IE browser that supports addEventListener
.
碰巧,支持onload
IE9也是第一个支持addEventListener
IE浏览器。
The whole thing looks like:
整个过程看起来像:
var first_html" title=js>js = document.getElementsByTagName('script')[0];
var html" title=js>js = document.createElement('script');
html" title=js>js.src = file;
if (html" title=js>js.addEventListener) { // normal browsers
html" title=js>js.addEventListener('load', function(){
alert('done!!');
}, false);
} else {
html" title=js>js.onreadystatechange = function() { // old IEs
if (html" title=js>js.readyState in {loaded: 1, complete: 1}) {
html" title=js>js.onreadystatechange = null;
alert('done!!');
}
};
}
first_html" title=js>js.parentNode.insertBefore(html" title=js>js, first_html" title=js>js);
Drawback is that you decide on a feature (script onload
support) based on a different feature (addEventListener
support). I can live with this. We're talking here about an exception for known legacy browsers and shouldn't be an issue going forward in this brave new world where everyone lives in piece and love and brotherhood and sisterhood and motherhood and all browsers support onload
and addEventListener
.
缺点是您基于其他功能( addEventListener
支持)决定功能(脚本onload
支持)。 我可以忍受。 我们在这里谈论的是已知的旧版浏览器的例外情况,在这个勇敢的新世界里,每个人都生活在零碎的爱情,兄弟情谊,姐妹情谊和母性中,所有浏览器都支持onload
和addEventListener
,这不应该成为一个问题。
So anyway, choose your poison 🙂
所以无论如何,选择你的毒药🙂
Here's a test page that listens to everything so you can play in different browsers: http://www.phpied.com/files/html" title=js>jsasync/loaded.html
这是一个测试页面,可监听所有内容,以便您可以在不同的浏览器中播放: http : //www.phpied.com/files/html" title=js>jsasync/loaded.html
BTW, notice that IE is the only browser that fires window.onload
before the onload
of the (slow) script. This is another thing to keep in mind and look out for.
顺便说一句,请注意IE是唯一一个在onload
(慢速)脚本之前触发window.onload
浏览器。 这是要记住并提防的另一件事。
Tell your friends about this post on Facebook and Twitter
在Facebook和Twitter上告诉您的朋友有关此帖子的信息
翻译自: https://www.phpied.com/async-html" title=html" title=java>javascript>html" title=java>javascript-callbacks/