同步与异部
JavaScript是一门单线程语言。单线程就意味着,执行任务时需要一个接着一个执行,前一个执行结束才能继续执行下一个任务。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。JavaScript的开发者在开发时想到了这一点,将等待执行的任务挂起,继续执行后面的任务,也可以说在执行栈中需要等待的任务放到任务队列中,等到主线程执行完成后将任务栈中的完成的任务拿出来进行执行。这就是所谓的同步任务与异步任务。
1、同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
2、当Event Table中指定的事情完成时,会将这个函数移入Event Queue。
3、主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
4、上述过程会不断重复,也就是常说的Event Loop(事件循环)。
5、我们不禁要问了,那怎么知道主线程执行栈为空啊?js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
JavaScript的宏任务与微任务
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
不同类型的任务会进入对应的Event Queue。
事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。
示例
var promise=new Promise((resolve)=>{ console.log(1) resolve() }) setTimeout(()=>{ console.log(2) }) promise.then(()=>{ console.log(3) }) var promise2=getPromise() async function getPromise(){ console.log(5) await promise; console.log(6) await promise2; console.log(7) } console.log(8) var promise3=new Promise((resolve)=>{ console.log(10) resolve() })
这段代码中,输出顺序是什么?
为什么会是这样?
因为以同步异步的方式来解释执行机制是不准确的,更加准确的方式是宏任务和微任务: 因此执行机制便为:执行宏任务 ===> 执行微任务 ===> 执行另一个宏任务 ===> 不断循环即:在一个事件循环中,执行第一个宏任务,宏任务执行结束,执行当前事件循环中的微任务, 执行完毕之后进入下一个事件循环中,或者说执行下一个宏任务