吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1787|回复: 0
收起左侧

[讨论] 用JavaScript在IE和Firefox中不同的运行效果,讨论其原理

[复制链接]
新手小渣渣 发表于 2019-8-16 15:24
本帖最后由 新手小渣渣 于 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 ?
直接获取的值.png

问题2、Firefox直接调用函数获取宽度返回值also为0,IE为实际宽度值
——
[JavaScript] 纯文本查看 复制代码
//第二种:直接命名函数,然后直接运行函数获取
    function cest1() {
        var ImgW1 = parseInt(image1.width);
        document.form1.cest1.value = ImgW1;
    }
    cest1();


直接调用方法你会发现返回值还是0 ??
直接调用函数获取的值.png

问题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也还是一样


setinterval获取的值.png

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(宽度值)


settimeout周期为0.png settimeout获取的值.png
      
看到这你应该会想,那就是调用问题了对吧,直接调用不行,就通过其他方法也就是通过“事件”来调用函数才可以获取宽度值
然而!然而你再看看哈

问题5、通过鼠标事件mouseover()方法调用函数获取的宽度值
——
[JavaScript] 纯文本查看 复制代码
//通过mouseover()方法调用函数外获取的宽度值:
    function cest4() {
        var ImgW4 = parseInt(image1.width);
        document.form1.cest4.value = ImgW4;
    }
image1.onmouseover = cest4();


大家请看效果——>>>>
mouseover获取的值.png
我还没把鼠标放到图片上呢,这里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;


效果图——>>>>>>
兼容性的mouseover.png

嗯??  这和兼容性有什么关系。。?增加了兼容性代码后不管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

原理图

         javascript引擎处理原理.png 注:异步机制中只允许一个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>


免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
Eric1 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-12 22:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表