我们知道JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成这门语言的核心特征,将来也不会改变。
所谓单线程是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。就是下面的讨论的同步和异步的概念。
同步:同步,是指代码从上向下执行,执行完一条,才去执行下一条,是按照顺序按照步骤的执行。比如,如果直接加载js文件,首先加载第一个文件a.js,并且执行这个js文件,完成后在加载b.js。这叫做同步:同步是在渲染DOM之前做的
异步,代码执行需要有一个过程,或者需要一定的时间,或者开始的时间不确定,这时候
我们先让别的不相关的代码执行,而当前代码当执行完成后去执行一个回调函数。
console.log("script start");
setTimeout(function(){
console.log("setTimeout");
},0)
Promise.resolve().then(function(){
console.log("promise1");
}).then(function(){
console.log("promise2");
})
console.log(‘script end‘);
正确答案是
要理解这些首先需要对事件循环机制处理宏任务和微任务的方式有所了解
每个线程都会有它自己的event Loop(事件循环),所以能够独立运行。然而所有的同源窗口会共享一个eventLoop以进行通信。event Loop会一直运行,来执行进入队列的宏任务。一个event Loop会宏任务源,这些宏任务源保证了本任务源内的顺序。但是浏览器每次都会选择源中的一个宏任务去执行。这保证可浏览器给与一些宏任务(如用户输入)以更高的优先级
浏览器为了能够使得JS内部Task与DOM任务能够有序的执行,会在一个task执行完毕结束后,在下一个task执行开始前,对页面进行重新渲染(render)
task->rander->task
鼠标点击会触发一个事件回调,需要执行一个宏任务,然后解析HTML.还有下面这个setTimeOut,setTimeOut的作用是等待给定的时间后回调产生一个新的宏任务。这就是为什么打印“setTimeOut”在打印“script end” 之后,因为打印“script end”是第一个宏任务里面的事情,而setTimeout 是更一个独立的任务里面的打印的。
异步有:setTimeout setInterval
微任务通常来说就是在当前task执行结束后立即执行的任务,比如对一系列动作做出反馈,或者是需要异步的执行任务而又不需要分配一个新的task,这样便可以减小一点性能的开销。只要执行栈中没有其他JS代码正在执行且每个宏任务执行完,微任务队列会立即执行。如果在微任务执行期间微任务队列中加入了新的微任务,就会把这个新的微任务加入到队列的尾部,之后也会被执行。微任务包括了promise async await。
一旦一个promise有了结果,或者早已有了结果(有了结果是指这个promise到了rejected状态),他就会为他的回调产生一个微任务,这就保证了回调异步执行的即使这个promise有了结果。所以对一个已经有了结果的promise调用.then()方法会立即产生一个微任务。这就为什么“promise1”,"promise2"会打印在“script end”之后,因为所有微任务执行的时候,当前执行栈的代码必须执行完毕。"promise1","promise2"会打印在"setTimeOut"之前,是因为所有的微任务总会在下一个宏任务之前全部执行完毕!
微任务有:promise async await
原文:https://www.cnblogs.com/my12-28/p/12796569.html