延迟0秒有啥用?这里就衍生出JS的代码执行流程的问题
大家都知道javascript是单线程,正常情况下javascript都是按照顺序执行的。但是我们可以让某段代码后面的代码先执行,这时就可以用到setTimeout延时0ms来实现了。如:
console.log(1)
setTimeout(function(){console.log(2); }, 0);
console.log(3)
执行的结果依次:1 3 2
之所以会出现这样结果是因为setTimeout(fn, 0)将console.log(2);
语句添加到了执行队列的队尾,即便只是延迟0ms也需要等栈中的同步任务都执行完毕后,再执行。因为栈中的同步任务也会耗时,所以间隔的时间一般会大于等于指定的时间,不会立即执行!
拓展知识
单线程与异步: js是单线程和异步,听到这句话是不是感觉很奇怪这两两者本身是相互矛盾的,理论上是不能同时存在的,因为是单线程,程序的执行顺序就是从上到下依次执行,同一时间内只能有一段代码被执行。
那么问题来了:当浏览器请求了一个返回非常慢的接口,那么页面就无法继续运行下去,页面卡住这就形成了“阻塞程序”,这显然是不对的。而且我们的浏览器本身就存在大量的异步请求,如果都需要一个个等待那么浏览器就无法正常运行了,这就注定js即使是单线程,也必须支持异步。那怎么办?
最终解决方式: 虽然JavaScript是单线程的,可是浏览器内部不是单线程的。那么js只执行自己程序的代码,当遇到异步操作时丢给浏览器,由浏览器的线程去执行丢入队列中,自己继续往下执行就能解决这个问题了。
- WebAPIs:浏览器为异步任务单独开辟的线程(服务JavaScript的,处理JavaScript的异步)
- 虚线部分:堆(heap)和栈(stack)共同组成了js主线程(这个就是我们JavaScript的线程)
- callback queue:任务队列,里面放着各种事件,比如我们点击所触发的事件,浏览器会帮我们以任务的形式,把他放入任务队列中
- event loop:任务循环,又叫事件循环。当所有主线程执行完毕后,所有的函数就都被推出了栈,而这个时候就会通过event loop(事件循环)去任务队列中将先前的异步操作推入栈中执行(就是我们异步的回调函数),但这个时候就不是异步操作了而是同步了。
总结
通过扩展知识的补充,想必大家都已经理解setTimeout(fun,0)的执行流程了。总的来说javascript一直都是单线程的,并没有去实现异步,而真正的异步操作是浏览器完成的。浏览器把异步操作通过回调行数的形式把任务丢到了队列中,当js的主线程都执行完毕,之后又会再去队列中将回调函数推入栈(stack)中继续执行。
1.js是单线程和异步原理视频
2.node的Event loop和javaScript 的Event loop 不同点
以上就是我对setTimeout和javascript单线程和异步机制的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的文章,以避免误人子弟。