共计 1399 个字符,预计需要花费 4 分钟才能阅读完成。
我们都知道在 JS 中 setTimeout 是异步执行机制的
像 setTimeout(function(){},0)这样
如果在这条语句后面还有很多的同步任务,它必须要等这些同步任务完成才会执行 setTimeout 里面的内容
setTimeout(function(){
不好意思,我要等 for 循环的同步任务完成才能执行
},0)
for(var i = 0; i < 99999999999; i++){
这里的任务完成了,才会执行 setTimeout 的内容
}
那么我所发现的这个问题如下:如代码所示:在 body 中插入两个 script 标签 <body>
<script>
alert(‘fir-script’);
setTimeout(()=>{
alert(‘setTime’);
},0);
</script>
<script>
alert(‘sec-script’);
var str = ‘ 测试的字符串 ’;
alert(str);
</script>
</body>
这里所用的测试字符串是中文这里需要做 3 个实验,分为 A、B、C
实验 A:用比较短的字符串,(有 5 个中文字体)来测试,执行的弹窗结果是:fir-script -> sec-script -> ‘ 测试字符串 ’ -> setTime
实验 B:用较长的字符串,(有 45000 个中文字体)来测试,结果发现了变化 执行的弹窗结果是:fir-script ->setTime -> sec-script -> ‘ 测试字符串 ’
实验 C:减少部分字符串,(有 43000 个中文字体)来测试,执行的弹窗结果是:fir-script -> sec-script -> ‘ 测试字符串 ’ -> setTime
在其他条件没有变化的情况下 (注意:三次测试 setTiemout 的时间都是 0) 程序执行的顺序似乎和字符串的长度有关(那其实可以说是和 script 里面的内容大小有关,那也可以进一步理解为和解析 script 内容的时间有关)
为了验证上述结论 (执行顺序和解析 script 内容的时间有关) 在实验 B 的基础上,对 setTiemout 的时间进行更改,其他保持不变如 B(5)为 5ms 后执行,即 setTimeout(()=>{alert(‘setTime’);},5); 下面我们看一下结果:
B(0): fir-script -> setTime -> sec-script -> ‘ 测试字符串 ’ B(5): fir-script -> setTime -> sec-script -> ‘ 测试字符串 ’ B(10): fir-script ->sec-script -> ‘ 测试字符串 ’ -> setTime B(15): fir-script -> sec-script ->’ 测试字符串 ’ -> setTime
从上面几个实验我们可以在侧面看出一个现象 setTime 不会出现在 sec-script 和 ‘ 测试字符串 ’ 之间,这也反映了 JS 是单线程执行的, 而且在同步任务里,不受其他 script 标签的影响
通过这个案例,发现了一些问题,总结如下:
如有其他外部脚本(即使这些脚本都是同步任务),像 setTiemout 这些异步任务,不会等待所有同步任务执行完成只有在同一个 script 标签里,异步任务要等待该标签的所有同步任务完成才会执行 因为需要去解析脚本,而解析脚本与执行另外的脚本不冲突
最后的最后,如果你在尝试过程中发现与本文的结果不相同,请把测试用的案例”加强“,如把字符串加到 10W,这是因为 setTimeout 的不确定性欢迎大家一起来探讨