本帖最后由 新手小渣渣 于 2019-8-16 15:39 编辑
今天下午敲代码发现了好几个问题,就单独写了十几行代码来凸显JavaScript在不同浏览器间线程处理原理
● 问题:
问题1、Firefox获取宽度返回值为0 ,IE为实际宽度值
——
[JavaScript] 纯文本查看 复制代码 <script type="text/javascript">
//第一种:不用任何函数直接获取
var ImgW = parseInt(image1.width);
document.form1.cest.value = ImgW;
</script>
直接获取你会发现宽度值一直为0 ?
问题2、Firefox直接调用函数获取宽度返回值also为0,IE为实际宽度值
——
[JavaScript] 纯文本查看 复制代码 //第二种:直接命名函数,然后直接运行函数获取
function cest1() {
var ImgW1 = parseInt(image1.width);
document.form1.cest1.value = ImgW1;
}
cest1();
直接调用方法你会发现返回值还是0 ??
问题3、通过setInterval()调用函数获取的宽度值--Firefox和IE(终于)返回值都为实际宽度值!
其实IE返回值全部都是宽度实际值,所以下边主要讨论的是Firefox
——
[JavaScript] 纯文本查看 复制代码 //[color=#000][font=宋体][size=9.6pt]通过setInterval()调用函数获取的宽度值[/size][/font][/color]:
function cest3() {
var ImgW3 = parseInt(image1.width);
document.form1.cest3.value = ImgW3;
}
setInterval('cest2()',1000); //周期设置为0也还是一样
Why? 同样都是调用函数来获取宽度的啊
然后那就再试试setTimeout()吧
问题4、通过setTimeout()调用函数获取的宽度值,按理说它应该和setInterval()方法(周期都设为0时也)一样的吧
但!在Firefox中——测试后你会发现它在周期设为0时的返回值有时候为0,有时候为实际宽度值(大多为实际宽度值)
而setInterval()方法不管周期多少,都是宽度实际值
——
[JavaScript] 纯文本查看 复制代码 //通过setTimeout()调用函数外获取的宽度值: function cest3() {
var ImgW3 = parseInt(image1.width);
document.form1.cest3.value = ImgW3;
}
setTimeout('cest3()',2000); //周期设为0后,有两种效果——返回值为0、返回值800(宽度值)
看到这你应该会想,那就是调用问题了对吧,直接调用不行,就通过其他方法也就是通过“事件”来调用函数才可以获取宽度值
然而!然而你再看看哈
问题5、通过鼠标事件mouseover()方法调用函数获取的宽度值
——
[JavaScript] 纯文本查看 复制代码 //通过mouseover()方法调用函数外获取的宽度值:
function cest4() {
var ImgW4 = parseInt(image1.width);
document.form1.cest4.value = ImgW4;
}
image1.onmouseover = cest4();
大家请看效果——>>>>
(我还没把鼠标放到图片上呢,这里IE也一样(但返回值不一样IE的为实际宽度值),都是加载完后直接就执行了,不用放鼠标。。)
问题6、关于mouseover()自动执行的问题,我就试了一下增加一行兼容性代码,居然好了???
——
[JavaScript] 纯文本查看 复制代码 //通过增加了兼容性的mouseover()方法调用函数外获取的宽度值:
function cest5(oEvent) {
if(window.event) oEvent = window.event;
var ImgW5 = parseInt(image1.width);
document.form1.cest5.value = ImgW5;
}
image1.onmouseover = cest5;
效果图——>>>>>>
嗯?? 这和兼容性有什么关系。。?,增加了兼容性代码后不管Firefox还是IE都是鼠标移到图片上方后才会执行
Why ??
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
有了问题,那么就是想办法探探其究竟了
欲探其因,先究其理
● 原理分析
一、JavaScript运行原理之线程与异步运行
JavaScript是单线程的,那么既然是单线程了,它的事件是如何异步运行的呢?单线程和异步运行机制其实并不冲突,我们只需了解其原理就都懂了。JavaScript引擎只有一个线程,迫使异步事件排队等待执行。
就像食堂打饭或者开水房打水一样,打水的人很多,但只有一个水龙头,你就必须得排队,至于排队的规则,学校不同排队规则可能也会有差异
这里的排队规则也是不同浏览器中处理JavaScript引擎处理下一事件的“处理规则”,异步事件又如何排队完全取决于各浏览器。
二、JavaScript中setTimeout()和setInterval()的区别
setTimeout()和setInterval()在执行异步代码的方式上有根本的不同。
举个例子:
[JavaScript] 纯文本查看 复制代码 setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);
表面上看两段代码运行效果是一样的,但其实有很大的差异!
不说执行时间间隔(涉及比较多,暂不做深究),就说回调时间的间隔:
setTimeout('function',delay)在上一次回调执行之后,至少有delay毫秒的延迟(最终可能会更多,但永远不会减少——因为要执行function里边的代码,所以一定会多多少少浪费点时间,而function代码执行完后再等delay毫秒后才会触发回调),而setInterval('function',delay)将尝试每delay毫秒执行一次回调,而不管上一次回调是什么时候执行的。
附 参考文献地址:How JavaScript Timers Work
原理图:
注:异步机制中只允许一个Interval排队等待,多余的会被直接删掉!(Dropped)
三、事件处理函数
下面请大家看这两行代码:
[JavaScript] 纯文本查看 复制代码 image1.onmouseover = cest4(); //这个指向的是一个结果,结果必然会导致先运行一遍,也就是会直接调用函数
image1.onmouseover = cest5; //这个指向的是cest方法,也就是事件发生后才会调用方法
image1.onmouseover = cest4();
执行这条语句的意思是image1指向的cest()运行的结果,而结果自然要运行出来才知道,所以cest函数就直接被调用了,于是不等鼠标over结果就自己出来了。 image1.onmouseover = cest5;
执行这条语句的意思是image1的鼠标事件指向一个叫cest名字的function.
给事件绑定函数的正确代码是 image1.onmouseover = cest5; 也就是不能在方法名后边加“( )”,加了括号的话就会直接执行函数!
虽然只差一个括号,但却有着本质的差别!
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
● 讨论问题:
问题1、问题2:
这两个问题都可以理解为Firefox对javascript代码异步处理太快,就是上述原理一中所说的“异步事件又如何排队完全取决于各浏览器。”
问题3、问题4:
setTimeout()只会执行一次,所以有可能异步太快,在图片加载完成前setTimeout()里边的函数已经执行完毕,以至于有时候获取到的宽度值为0,而有时获取的宽度值为实际宽度值
setInterval()在Firefox中的异步处理先不说快不快,但我们已经知道是不间断地一直执行着的,所以就算第一次因为异步处理太快,也还会一直循环执行setInterval()里边的函数,然后图片加载完后还会获取到实际宽度值
问题5、问题6:
看完原理部分后,我们也就应该知道了其实不是做了兼容性处理onmouseover事件才正常的,而是函数绑定事件的方法有误。
● 总结:
代码并不难,JavaScript小白也能看得懂,但它的确能凸显出很多实际问题,主要就是通过这些代码来讲一些原理。
ps:本帖为讨论帖,本人技术也不怎样,可能帖子里也会有错,大家可以多多讨论哈!
——————————————————————————————————————————————————————————————————————
下边附上全部代码:
[JavaScript] 纯文本查看 复制代码 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>获取图片宽度值</title>
</head>
<body>
<input name="image1" type="image" id="image1" src="4.jpg" border="0" >
<form name="form1">
<tr>
<td>cest方法外获取的宽度值:</td>
<input type="text" name="cest" ><br>
<td>cest1方法内获取的宽度值:</td>
<input type="text" name="cest1" ><br>
<td>通过setInterval()调用函数获取的宽度值:</td>
<input type="text" name="cest2" ><br>
<td>通过setTimeout()调用函数获取的宽度值:</td>
<input type="text" name="cest3" ><br>
<td>通过mouseover()方法调用函数获取的宽度值:</td>
<input type="text" name="cest4" ><br>
<td>通过增加了兼容性的mouseover()方法调用函数获取的宽度值:</td>
<input type="text" name="cest5" ><br>
</tr>
</form>
<script type="text/javascript">
//第一种:不用任何函数直接获取
var ImgW = parseInt(image1.width);
document.form1.cest.value = ImgW;
//第二种:直接命名函数,然后直接运行函数获取
function cest1() {
var ImgW1 = parseInt(image1.width);
document.form1.cest1.value = ImgW1;
}
cest1();
//第三种:通过setInterval()来调用cest2函数获取
function cest2() {
var ImgW2 = parseInt(image1.width);
document.form1.cest2.value = ImgW2;
}
//第四种:通过setTimeout()调用函数外获取的宽度值:
function cest3() {
var ImgW3 = parseInt(image1.width);
document.form1.cest3.value = ImgW3;
}
//第五种:通过mouseover()方法调用函数外获取的宽度值:
function cest4() {
var ImgW4 = parseInt(image1.width);
document.form1.cest4.value = ImgW4;
}
//第六种:通过增加了兼容性的mouseover()方法调用函数外获取的宽度值:
function cest5(oEvent) {
if(window.event) oEvent = window.event;
var ImgW5 = parseInt(image1.width);
document.form1.cest5.value = ImgW5;
}
image1.onmouseover = cest4();
image1.onmouseover = cest5;
setInterval('cest2()',1000); //周期设置为0也还是一样
setTimeout('cest3()',0); //周期设为0后,有两种效果——返回值为0、返回值800(宽度值)
</script>
</body>
</html>
|