JS中,script(整体代码)是怎么入栈的?

在看js事件循环机制的解释时,经常看到如下说明:

任务队列分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为taskjobs

macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering

micro-task大概包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)

而后开始解释事件循环的流程,当执行栈为空时,事件循环先从一个macro-task开始,然后执行所有的micro-task,再执行一个macro-task,balabala...

那么问题来了,在第一次执行事件循环的时候,通常都会这样说

事件循环从宏任务队列开始,这个时候,宏任务队列中,只有一个script(整体代码)任务。

想知道script(整体代码)是怎么作为macro-task入栈的?
比如说,setTimeoutajax在浏览器中都有对应的webApi模块去处理,script(整体代码)应该是先编译成指令存在指令区,然后开始执行的吧。这个过程是怎么变成task任务,进而添加到队列里的,为啥不是直接入栈呢?

求各位大神解答!

文章引用:
前端基础进阶(十二):深入核心,详解事件循环机制

阅读 4.7k
2 个回答
(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);
})()

那这道题目举例吧。
为什么输出结果是1,2,3,5,4而非1,2,3,4,5?

既然你已经知道怎么分类了,不就不赘述了。直接说说macrotasks和microtasks的执行顺序吧:

  1. 主js作为macro先入队列,编号ma1
  2. 执行到setTimeout...,回调作为macro入队列,编号ma2
  3. 执行到new Promise...,then作为micro入队列,编号mi1
  4. ma1执行完之前,调用mi1,mi1执行完以后,ma1也就正式的结束了
  5. ma2开始执行

可以认为macro是主人,micro是奴隶,哪个macro创建了micro,micro就管它叫主人。
ma1快死之前,对奴隶mi1说,我要挂了,你一起陪葬吧,mi1说好的便上吊了,ma1看mi1死后,也就安心的去了。
然后ma2也准备要死了,,,

总的来说就是,macro作为主导,它有支配micro的能力,在一个macro任务消灭之前,它会让它创建的micro任务都执行完,然后才进入下一个macro任务。
然后,入栈出栈,这个另一个概念,是每个task执行它的代码的时候发生的,比如变量定义,函数调用,通过栈的入出,计算出结果。

"script(整体代码)应该是先编译成指令存在指令区,然后开始执行的吧"这句话有误,javascript是一门解释型的语言,它是被js引擎所边解释边执行的,没有“先编译成指令存在指令区”一说......

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏