聊聊前端面试之输出顺序

春节后,新一轮跳槽风暴不知道可否吹暖今冬的裁人寒冬。然而,职场现状就是愈来愈多的小公司也在效仿各大互联网牛场面试要求,对于底层知识要求愈来愈深,管他用着用不着的,先面了再说。本篇跟你们聊聊面试常见题型之显示顺序问题。web

注:本篇分析为在浏览器环境中排序显示。
面试

Nodejs编程是全异步,事件引擎为libuv。
编程

1、JavaScript运行机制

关于运行机制聊四个关键点:浏览器

  • 单线程:同一时间只能解决一件事,是JS核心特征。JS为何不能多线程?由于JS是浏览器脚本语言,主要用于用户交互与DOM操做;
  • 任务类型:同步任务异步任务。同步任务是主线程上的排队等待解决的任务,只有完成一项任务,才能够进行下一个任务;异常任务,不进入主线程任务,而是进入“任务队列”,只有主线程的任务完成后,才会召唤“任务队列”上任务并执行;
  • 任务队列:是一个事件队列,I/O设备完成一项任务,就会在“任务队列”里添加一个事件。注意,必须I/O设备完成有结果,才会进入到“任务队列”;
  • 事件循环(Event Loop):主线程不断的循环从“任务队列”读取事件的运行机制。

2、任务的阶级斗争

JavaScript任务运行机制图
bash

第一阶级:同步任务

一、皇帝豪饮两碗鹿血,问有个叫EventLoop的公公,今晚谁来陪睡,EventLoop掐指一算,正宫几个“同步任务“娘娘都送过礼,我就按照送礼顺序来给她们安排吧。多线程

同步任务优先执行,先进先出。
异步

第二阶级:异步任务(微任务)

二、几晚事后,全部送过礼的“同步任务”娘娘轮流服侍皇帝一遍。如此同时,秀宫的宫女们忙着化妆整容。原来,宫里有个不成文的规定,只有收拾好本身的宫女才能够排队等待皇帝的召唤,到时候公公EventLoop会按照排队次序向皇帝安排服侍。async

三、何时才轮到宫女们服侍呢?是“同步任务”娘娘们服侍一遍后,毕竟公公EventLoop为了保护本身的饭碗,得让皇帝不断尝鲜。函数

同步任务执行的同时,异步任务在事件栈完成后,异步任务进入“任务队列”;
oop

事件循环(Event Loop)驱使主线程在所有同步任务完成后,从“任务队列”读取事件,如此不断循环;

任务队列执行先进先出;

第三阶级:异步任务--定时器(宏任务)

四、在秀宫有两个宫女姓SetTimeout和setInterval,人老珠黄,虽然化妆技术还能够,也送过了礼,无奈确实不上档次,负责秀宫的公公就让她俩排在了全部宫女的后边,等着呗。

五、这俩宫女终于看到但愿了,可谁知又来一批年轻漂亮的秀女,怎么办,等着呗。

六、终于,前先后后好几批年轻秀丽的宫女们服侍完皇帝,轮到这两位了,按照老规则,谁先来的谁优先,俩人对视苦笑,回头一看,又来几个姓SetTimeout和setInterval的宫女...

同时嵌套在异步操做的任务,会将嵌套在异步的下一次任务队列中;

定时器任务添加到任务队列的尾部;

3、案例分析

基于今日头条的面试题改造

async function async1() {
    console.log(1)
    await async2()
    console.log(2)
    return await 3
}
async function async2() {
    console.log(4)
}

setTimeout(function() {
    console.log(5)
}, 0)

async1().then(v => console.log(v))
new Promise(function(resolve) {
    console.log(6)
    resolve();
    console.log(7)
}).then(function() {
    console.log(8)
})
console.log(9)复制代码
  • 从代码第一行开始,异步函数async一、async2构建完未执行。
  • 按照代码顺序,首先该执行的应该是setTimeout,怎奈又不是正宫,长得又不秀丽,只能在任务队列最后等着。
  • 运行到async1.then()时,async1返回一个Promise对象(异步函数实际上是封装的Promise.resolve()Promise对象是一个构造函数),因此在执行async1时,首先将非resolve、reject函数加入主线程,上题中首先执行console.log(1)await async2
    输出1,4。感受await挺孙子的,执行完本身的函数就跳出来async函数。
  • 继续看,异步函数async1的then执行这个时候进入事件栈,由于还在等待异步函数async1返回值,等着吧。
  • 继续向下执行遇到真正的Promise对象了,二话不说,执行下先,console.log(6)console.log(7)直接加入到主线程,输出6,7。同时将异步函数console.log(8)放在储秀宫,虽然属于第二阶级,起码仍是第二阶级的老大么。
  • 单纯的console.log(9)说,咱也是第一阶级的,虽然最后一位,侍架一晚,输出了
    9
  • 同步人物结束了,Event Loop开始召唤任务队列,console.log(8)说我是秀女中的第一位,好,就你了。因而,生出了8
  • setTimeout翘首以盼,谁知,执行完本轮又跳到到异步函数async1,率先看到了console.log(2),因此输出了2
  • 紧接着,又遇到了await了,还好,结束了,返回的值扔给了async的异步函数,获得了值,抓紧时间执行,获得结果了,终于能够进入任务队列,这时主线程也是空的,执行下结果吧,输出了3
  • 全部微任务结束了,该宏任务大展拳脚了,setTimeout输出了值,5
以上试题分析完毕,输出结果顺序为: 1,4,6,7,9,8,2,3,5

4、最后

以上是我的对于任务执行顺序的理解,如理解有误,但愿大神多多指教。

相关文章
相关标签/搜索