1、 js引擎是单线程的还是多线程的?
从表面看来,setTimeout()、ajax异步请求、回调函数这些js中比较重要的特性看起来是多线程的,但是js引擎却是 单线程 的。时至今日,HTML5中已经提出了web worker标准,允许js脚本去创造多个线程,但是这些线程中只有一个主线程,而且其他线程都受主线程的控制,所以,js的本质依然是单线程。但是我们都知道,单线程只能在同一时间处理一件事务,那么这一定会有效率差的问题,因为,当前事务的处理,一定会堵塞事件队列中的其他事务的执行。而某些耗时的io操作,比如键盘输入,比如ajax于是js引入了 异步 的解决方案,采用了 event loop 机制去将耗时的io操作放入事件队列(所谓 事件队列 ,就是只有前一个事件执行完毕,后一个事件才会继续执行)中去,先去执行下一个事务操作,而那些放入到队列中的耗时的io操作(比如ajax)在执行完毕之后,javascript会将异步方法的执行结果放入到事件队列中,等待执行。
而正是因为javascript的非阻塞的io事件处理模型,node才最终选择了js,大大推动了js在服务端的发展。
2、浏览器是多线程的
js引擎线程只是浏览器中的一个线程。通常浏览器会有三个线程:js引擎线程、GUI线程(用于渲染视图)、浏览器时间触发线程(用于用户对浏览器的控制交互)
3、js引擎采用单线程机制,这和js的诞生有关:
js被创造出来用于实现操作浏览器html中的DOM树、CSS样式树以及实现界面中用户与html中DOM的动态交互,那么问题来了,假如js是多线程执行,那么很可能出现同一时刻有两个线程在操作同一个UI DOM元素,并且假如一个线程用于给DOM元素添加样式,而另一个线程用于删除DOM元素。这时候,这个DOM就成为了 临界资源,浏览器就无法去裁决究竟以哪一个线程的操作为准。虽然,我们也可以实现某些 锁 来规避这种线程操作互斥的情况,但是这一定会给js开发带来更大的复杂性。所以js最终采用单线程机制。
4、setTimeout()
setTimeout()方法有两个参数,第一个参数为一个 函数,第二个参数是一个时间。
首先看这个代码: setTimeout(function hello(),1000);
内部的运行顺序:在js引擎执行完该行js代码之后,会在1000毫秒之后会把hello()这个函数放入到事件队列中。等到事件队列中排在hello()之前的任务执行完毕后,hello()得到执行。所以setTimeout方法中设置的时间为1000毫秒,只是说明在setTimeout()方法运行之后的1000毫秒时,把setTimeout方法的第一个参数:hello()函数放入到事件队列中准备执行。注意,这里是准备执行,而不是立即执行。所以,在setTimeout()方法执行后,到hello()执行的 时间差 总是大于1000毫秒的。