事件循环EventLoop

进程与线程

相信大家经常会听到 JS 是单线程执行的,但是你是否疑惑过什么是线程?
讲到线程,那么肯定也得说一下进程。本质上来说,两个名词都是 CPU工作时间片的一个描述。进程描述了 CPU 在运行指令及加载和保存上下文所需的时间,放在应用上来说就代表了一个程序。线程是进程中的更小单位,描述了执行一段指令所需的时间。
把这些概念拿到浏览器中来说,当你打开一个 Tab 页时,其实就是创建了一个进程,一个进程中可以有多个线程,比如渲染线程、JS 引擎线程、HTTP 请求线程等等。当你发起一个请求时,其实就是创建了一个线程,当请求结束后,该线程可能就会被销毁。

什么是执行栈

可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。
当开始执行 JS 代码时,首先会执行一个main函数,然后执行我们的代码。根据先进后出的原则,后执行的函数会先弹出栈,在图中我们也可以发现,foo函数后执行,当执行完毕后就从栈中弹出了。
平时在开发中,大家也可以在报错中找到执行栈的痕迹。


    function foo() {
      throw new Error('error')
    }
    function bar() {
      foo()
    }
    bar()

当我们使用递归的时候,因为栈可存放的函数是有限制的,一旦存放了过多的函数且没有得到释放的话,就会出现爆栈的问题。

function bar() {
  bar()
}
bar()

同步任务、异步任务、微任务与宏任务

同步任务: 指的是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
异步任务: 指的是不进入主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
宏任务:script(全局任务),setTimeout,setInterval,setImmediate,I/O,UI rendering。
微任务:process.nextTick,promise,object.observer,MutationObserver。
在这里插入图片描述
面试题:

console.log(1);
setTimeout(()=>{
    console.log(2);
    Promise.resolve().then(()=>{
        console.log(3);
    })
});
new Promise((resolve,reject)=>{
    console.log(4);
    resolve(5);
}).then((data)=>{
    console.log(data)
})
setTimeout(()=>{
    console.log(6)
})
console.log(7)

打印结果为:1 4 7 5 2 3 6
解析:执行全局Script,直接输出1,后面的setTimeout为宏任务
new Promise相同于同步任务,输出4,后面的.then()加入到微任务队列中,后面的setTimeout为宏任务
接着执行全局Script,直接输出7
执行完所有的宏任务后,接着在微任务队列中的所有,输出5
接着执行剩下的宏任务,输出2
然后执行上一步红任务产生的微任务,输出3
最后执行最后一个setTimeout宏任务,输出6

猜你喜欢

转载自blog.csdn.net/weixin_36430673/article/details/100980580
今日推荐