今天和朋友讨论了一个js 线程的问题  千言不如一例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<script>
    function fun1() {
        setTimeout(function(){alert(1);},0)
        while(true) {};
    }
</script>
<body>
    <div id="div1">abc</div>
    <input type="button" value="测试" onclick="fun1();">
</body>
</html>



如果按照以前js 顺序执行的思路来理解 那么点击测试按钮后 应该会先弹出alert(1) 然后死循环 (错 了)
但是结果却是 点击按钮后直接死循环 

出现這个问题的主要原因是对SetTimeout這个函数不清楚, 对javascript 单线程的理解不清楚造成的。

首先我们对浏览器中的线程了解一下



 通常一个浏览器会至少存在三个线程:JS引擎线程(用于处理JS)、GUI渲染线程(用于页面渲染)、浏览器时间触发线程(用于控制交互)。 而因为JS可以操作DOM元素,进而会影响到GUI的渲染结果,因此JS引擎线程与GUI渲染线程是互斥的。也就是说当JS引擎线程处于运行状态时,GUI渲染线程将处于冻结状态。 JS引擎是基于事件驱动,采用的是单线程运行机制。即JS引擎会只会顺序的从任务列表中取任务,并执行。

 SetTimeout/SetInternal

S引擎本身就只能单线程运行,因此定时器需要由其他的外部线程来启动。所以对JS引擎而言,定时器线程可以被视为异步线程。但当定时器时间到达后,所触发的事件则必须在任务列表中排队,等候JS引擎的处理。



那么就不难理解了 



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<script>
    function fun1() {
        //--------任务1--------
        setTimeout(function(){alert(1);},0) //调用外部线程 后立即将代码push到js引擎的任务列表中 ---------任务2---------
        while(true) {};
    }
    //所以任务列表中的顺序应该是 
    //[
    //  任务1,--死循环 因为js非阻塞的机制 所以导致代码不会执行到任务2
    //  任务2
    //]
</script>
<body>
    <div id="dom1">abc</div>
    <input type="button" value="测试" onclick="fun1();">
</body>
</html>



好了 铺垫已经打好了 接下来进入正题 dome操作也类似  



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<script>
    function fun1() {
        //--------任务1--------
        document.getElementById('dom1').innerHTML = 123; //因为操作了dome 所以得调用外部线程(GUI渲染线程)JS引擎线程与GUI渲染线程互斥 所以dome操作冻结 (可以理解为添加了一个任务2在S引擎的任务列表里面么?)-------任务2--------

        while(true) {}; //不需要调用外部线程 所以這个循环属于任务1
    }
    //所以任务列表中的顺序应该是 
    //[
    //  任务1,--死循环 因为js非阻塞的机制 所以导致代码不会执行到任务2
    //  任务2
    //]

//最后有点疑问 如果我用debugger去调试的话 确会改变dom1的内容为123 然后才会进入循环????
</script>
<body>
    <div id="dom1">abc</div>
    <input type="button" value="测试" onclick="fun1();">
</body>
</html>



setTimeout 的妙用



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<script>
    function fun1() {
        //--------任务1--------
        document.getElementById('dom1').innerHTML = 123; //因为操作了dome 所以得调用外部线程(GUI渲染线程)JS引擎线程与GUI渲染线程互斥 所以dome操作冻结 (可以理解为添加了一个任务2在S引擎的任务列表里面么? 任务列表Array.push(任务2) )-------任务2--------

        setTimeout(function(){while(true) {};},0); //调用外部线程 然后将触发的事件添加到任务列表中 -----任务3-----
    }
    //所以任务列表中的顺序应该是 
    //[
    //  任务1,
    //  任务2, --dome操作
    //  任务3, --循环
    //]
</script>
<body>
    <div id="dom1">abc</div>
    <input type="button" value="测试" onclick="fun1();">
</body>
</html>