聊聊前端面试之输出顺序

栏目: JavaScript · 发布时间: 5年前

内容简介:春节后,新一轮跳槽风暴不知道能否吹暖今冬的裁员寒冬。然而,职场现状就是越来越多的小公司也在效仿各大互联网牛场面试要求,对于底层知识要求越来越深,管他用着用不着的,先面了再说。本篇跟大家聊聊面试常见题型之显示顺序问题。注:本篇分析为在浏览器环境中排序显示。Nodejs编程是全异步,事件引擎为libuv。

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

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

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

一、JavaScript运行机制

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

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

二、任务的阶级斗争

JavaScript任务运行机制图

第一阶级:同步任务

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

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

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

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

3、什么时候才轮到宫女们服侍呢?是“同步任务”娘娘们服侍一遍后,毕竟公公EventLoop为了保护自己的饭碗,得让皇帝不断尝鲜。

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

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

任务队列执行先进先出;

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

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

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

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

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

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

三、案例分析

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

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)复制代码
  • 从代码第一行开始,异步函数async1、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

四、最后

以上是个人对于任务执行顺序的理解,如理解有误,希望大神多多指教。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

MacTalk 人生元编程

MacTalk 人生元编程

池建强 / 人民邮电出版社 / 2014-2-1 / 45

《MacTalk·人生元编程》是一本随笔文集,主要内容来自作者的微信公众平台“MacTalk By 池建强”。本书撰写于2013年,书中时间线却不止于此。作者以一个70 后程序员的笔触,立于Mac 之上,讲述技术与人文的故事,有历史,有明天,有技术,有人生。70 多篇文章划分为六大主题:Mac、程序员与编程、科技与人文、人物、工具、职场。篇篇独立成文,可拆可合,随时阅读。 此外,作者还对原来......一起来看看 《MacTalk 人生元编程》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具