Open huandie2012 opened 5 years ago
JS 是单线程语⾔,一切javascript版的"多线程"都是用单线程模拟出来的。 JS是按照语句出现的顺序执⾏行的
let a = '1' console.log(a) let b = '2' console.log(b) //1 2
然⽽,实际上代码执⾏的顺序并不是按照出现的顺序执⾏行:
setTimeout(function(){ console.log('one') }); console.log('two') // two one
这是为什什么呢? JS为什什么是单线程的 原因在于:JS的用途。JS是浏览器脚本语⾔,其主要的作⽤是与⽤户交互、操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,⼀个线程在某个DOM节点上添加内容,另一个线程删除了了这个节点,这时浏览器器应该以哪个线程为准? 为了利⽤多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是⼦线程完全受主线程控制,且不不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。 Web Worker:主线程可以采⽤用new命令,调⽤用Worker()构造函数,新建⼀一个 Worker线程。具体可参考:Web-Worker 同步任务和异步任务 由于JS是单线程,所以任务执⾏都是一个⼀个执⾏,前⼀个执⾏完了之后,才能执⾏下⼀个任务,如果前⼀个任务阻塞了,后⾯面的任务只能等待。 如此,将会造成资源的浪费。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输⼊入输出设备)很慢(⽐比如Ajax操作从⽹网络读取数据),不得不等着结果出来,再往下执行。 JavaScript语⾔的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运⾏排在后⾯的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。 因此,JS设计者将所有任务分为:
JS执行的运行机制如下:
let data = []; $.ajax({ url:www.javascript.com, data:data, success:() => { console.log('发送成功!'); }}) console.log('代码执⾏行行结束');
⽤用JS的执⾏行行机制分析:
为什什么这段代码不不是按照顺序执⾏行行的? setTimeout和setInterval
setTimeout(() => { task() },3000) sleep(10000000)
为什什么rask()等待执⾏行行的事件超过3秒?执⾏行行过程分析:
console.log('先执⾏行行这⾥里里'); setTimeout(() => { console.log('执⾏行行啦') },0);
关于setTimeout要补充的是,即便便主线程为空,0毫秒实际上也是达不不到的。根据HTML的标准,最低是4毫秒。 setInterval会每隔指定的时间将注册的函数置⼊入Event Queue,如果前⾯面的任务耗时太久,那么同样需要等待。 对于setInterval(fn,ms)来说,我们已经知道不不是每过ms秒会执⾏行行一次fn,⽽而是每过ms秒,会有fn进⼊入Event Queue。一旦setInterval的回调函数fn执⾏行行时间超过了了延迟时间ms,那么就完全看不不出来有时间间隔了了。 宏任务和微任务 除了了⼴广义的同步任务和异步任务,任务可以更更精细的定义为:
事件循环的顺序,决定js代码的执⾏行行顺序。进⼊入整体代码(宏任务)后,开始第⼀一次循环。接着执⾏行行所有的微任务。然后再次从宏任务开始,找到其中⼀一个任务队列列执⾏行行完毕,再执⾏行行所有的微任务。例如:
setTimeout(function() { console.log('setTimeout'); }) new Promise(function(resolve) { console.log('promise'); resolve('ok') }).then(function() { console.log('then'); }) console.log('console');
// 输出结果 promise console then setTimeout
事件循环,宏任务,微任务的关系如图所示: 最后,我们来看个例子:
console.log('1'); setTimeout(function() { console.log('2'); new Promise(function(resolve) { console.log('3'); resolve(); }).then(function() { console.log('4') }) }) new Promise(function(resolve) { console.log('5'); resolve(); }).then(function() { console.log('6') }) setTimeout(function() { console.log('7'); new Promise(function(resolve) { console.log('8'); resolve(); }).then(function() { console.log('9') }) })
有兴趣的小伙伴可以执行一下代码看最后的结果。 (结果是:156234789) 事件执行顺序的题目 总结: 关于js是单线程语言的理解:js本身是单线程,但执行js的环境(浏览器,node)是多线程的
JS 是单线程语⾔,一切javascript版的"多线程"都是用单线程模拟出来的。 JS是按照语句出现的顺序执⾏行的
然⽽,实际上代码执⾏的顺序并不是按照出现的顺序执⾏行:
这是为什什么呢? JS为什什么是单线程的 原因在于:JS的用途。JS是浏览器脚本语⾔,其主要的作⽤是与⽤户交互、操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,⼀个线程在某个DOM节点上添加内容,另一个线程删除了了这个节点,这时浏览器器应该以哪个线程为准? 为了利⽤多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是⼦线程完全受主线程控制,且不不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。 Web Worker:主线程可以采⽤用new命令,调⽤用Worker()构造函数,新建⼀一个 Worker线程。具体可参考:Web-Worker 同步任务和异步任务 由于JS是单线程,所以任务执⾏都是一个⼀个执⾏,前⼀个执⾏完了之后,才能执⾏下⼀个任务,如果前⼀个任务阻塞了,后⾯面的任务只能等待。 如此,将会造成资源的浪费。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输⼊入输出设备)很慢(⽐比如Ajax操作从⽹网络读取数据),不得不等着结果出来,再往下执行。 JavaScript语⾔的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运⾏排在后⾯的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。 因此,JS设计者将所有任务分为:
JS执行的运行机制如下:
⽤用JS的执⾏行行机制分析:
为什什么这段代码不不是按照顺序执⾏行行的? setTimeout和setInterval
为什什么rask()等待执⾏行行的事件超过3秒?执⾏行行过程分析:
关于setTimeout要补充的是,即便便主线程为空,0毫秒实际上也是达不不到的。根据HTML的标准,最低是4毫秒。 setInterval会每隔指定的时间将注册的函数置⼊入Event Queue,如果前⾯面的任务耗时太久,那么同样需要等待。 对于setInterval(fn,ms)来说,我们已经知道不不是每过ms秒会执⾏行行一次fn,⽽而是每过ms秒,会有fn进⼊入Event Queue。一旦setInterval的回调函数fn执⾏行行时间超过了了延迟时间ms,那么就完全看不不出来有时间间隔了了。 宏任务和微任务 除了了⼴广义的同步任务和异步任务,任务可以更更精细的定义为:
事件循环的顺序,决定js代码的执⾏行行顺序。进⼊入整体代码(宏任务)后,开始第⼀一次循环。接着执⾏行行所有的微任务。然后再次从宏任务开始,找到其中⼀一个任务队列列执⾏行行完毕,再执⾏行行所有的微任务。例如:
事件循环,宏任务,微任务的关系如图所示: 最后,我们来看个例子:
有兴趣的小伙伴可以执行一下代码看最后的结果。 (结果是:156234789) 事件执行顺序的题目 总结: 关于js是单线程语言的理解:js本身是单线程,但执行js的环境(浏览器,node)是多线程的