硬性知识点考察:

为什么js是单线程的?

  因为js设计最初是为了操作dom而生,如果是多线程的,当多个线程同时修改一个dom时就会产生冲突,所以设计成单线程,一次只能做一件事。

既然是单线程为什么要有异步?

  还是因为js要和用户进行交互,对于一些耗时比较长的任务或者需要用户操作的事件任务,如果不使用异步,就会造成程序阻塞,那样用户不操作页面就永远卡死在某一处了。所以需要异步单独处理这一类任务。

js怎么实现异步的?

  通过event loop事件循环实现,耗时任务由浏览器的web apis异步线程执行,条件成立触发回调,同步的任务和异步的回调任务通过事件循环被执行。

2018.11.19 周一面试题:js单线程导致的异步任务

考题:

var i = 5;
while(i--){
setTimeout(function(){
console.log(i)
},0)
}
console.log(666)

考点:

  1. while循环语句、隐式类型转换
  2. i - - 和 - - i 的区别
  3. 同步和任务队列
  4. 异步事件之定时器线程

答案:先执行 666 ,然后输出5个 -1

解析考点:

while(){}

就是一个循环语句,判断小括号内的条件,成立则执行大括号内的语句,否则结束循环。

就是0和非0会被隐式转换为true or false

隐形考点,while小括号内部,会进行隐式转换,将其他类型的值转为Boolean布尔值类型的进行判断

劝你别去试while(-1){console.log("I'm fantastic!")}。因为我刚才就是导致浏览器死机,然后关掉重写的博文【多么痛的领悟】

--i 和 i-- 

var i = 5;
while(--i){
setTimeout(function(){
console.log(i)
},0)
}
console.log(666)

那么结果就是这样了,输出4个0。

这是因为呢,

【i--】 这里的顺序,是先输出i,再执行i=i -1;

【--i】只是先做i=i -1;然后输出i;

也就是说,while(i--)的时候,是先判断i是否满足条件,然后再执行增减。

而while(--i)的时候,是先让i减一再去判断是否满足条件。

所以第一种情况中,i为0的时候被判断不满足条件,不再执行setTimeout,但是后边还是要再-1的,所以最后i变成了-1。

而第二种情况,当i等于1的时候,先让1-1,然后在判断0不满足条件,不再执行i为1时的条件语句,所以循环只有4次,且i最终值也为0。

setTimeout定时器导致的 异步任务

js是单线程的,而浏览器是多线程的。setTimeout属于定时器触发线程中的一种。

因为不能保证任务能够立马执行,所以他被扔到异步队列中,等待回调函数召唤,到时间后再执行。

等时机成熟,回调函数会被安排到主队列中排序入栈被执行。注意这里不要被定时器的时间迷惑了。

理论上执行的时间并不一定就是代码执行时定时器设定的延迟时间之后的时间。因为如果定时器到时,

主任务队列上还轮不着他说话的时候,他也不能插嘴。

同步和任务队列

因为遇到循环里的异步定时器事件,定时器内部的任务被扔到任务队列,等待同步任务执行完毕后执行。

所以循环完毕后,外边的console.log(666)按照同步的顺序先被执行并打印出来。而不是循环内部的console先起作用

2018.11.20 周二面试题:主任务队列上的同步任务与异步回调

考题:

     setTimeout(function () {
console.log(1);
}, 0);
function foo() {
console.log(2);
}
function bar() {
console.log(3);
}
bar();
setTimeout(function () {
console.log(4);
}, 1000);
foo();
setTimeout(function () {
console.log(5);
}, 0); 

考点:

同步任务

异步回调函数

定时器

解析:

答案是:3,2,1,5   约1秒后, 4

主要还是定时器的考点吧。不要被代码的书写顺序所疑惑。

首先,定时器出发前,所有的定时器任务都是当做异步任务被扔到异步“等待池”的。

当定时器触发时,异步的等待任务才会以回调函数的形式加入主队列中,然后根据定时器的时间来排回调函数的具体执行顺序。

所以,上边的代码中,虽然console(1) 按照代码顺序在上边。

但是优先处理的同步任务是bar(),其次是far()。也就是会先console(3)、console(2)执行

等这些同步任务全部执行完毕清空栈空间后,异步定时器任务才会按序执行(事件点击和请求除外)。

而按照定时器的顺序,两个定时器延迟时间为0的先执行,因为console(1)在上边,所以1比5先输出。

2018.11.21 周三面试题:连等赋值问题、运算符优先级

题目代码:

 var a = {n:1};
var b = a;
a.x = a = {n:2};
console.log(a.x)
console.log(b.x)

考点:

  1. js堆栈空间
  2. 引用值拷贝(浅拷贝)
  3. 连等赋值的顺序(从右向左)
  4. “.”运算符赋值的优先级(高于等号赋值的顺序)
  5. 对象的属性不存在时,直接获取得到undefined。变量不存在时直接获取会报错:变量名 is not defined

答案与解析:

首先要知道的是,在js中,引用类型的值,在栈中存了个地址,指向堆内存中的真正位置和数据。

而引用类型的值再拷贝,新的变量拿到的还是这个地址,并在栈内存中开辟一块土地放置这个地址,同样指向源值在堆中的位置。

举个例子,

变量小明,公安局给他制作一个身份证,身份证上的地址是北京。

儿子变量小小明,公安局制作一个新的身份证,但是身份证上的地址也还是北京。具体位置不变。

套到上例,变量a,存放在栈内存中。其值是一个指针,指向堆内存中的 {n:1}。

var b = a;

先执行var b;然后b = a;

所以b在栈内存也开辟了一个新空间。然后新空间放一个内容就是和a的内容一致的、指向堆内存{n:1}的指针。

所以,b此时等于{n:1};

好,接下来重头戏来了:

a.x = a = {n:2}

首先要知道,js中变量连等赋值是从右向左的。

那我们就会理解为先是a = {n:2},然后a.x = {n:2}。

这样理解就掉坑里了。

这道题中一个关键的考点是有一个 . 运算符。这个点运算符的优先级高于 = 赋值运算符

所以这一句连等的正确执行顺序应该是

a.x = {n:2}; // 此时b = a = {n:1,x: {n: 2}};获取b.x就是对象{n:2}
a = {n : 2}; // 此时整个a被重新赋值,a在栈内存中的指针指向了{n:2}这个对象,所以里边没了x属性,console.log(a.x)不报错,拿到的是undefined值。

此时的堆栈空间关系如图:

2018.11.22 周四面试题:同步任务、异步任务、宏任务与微任务的优先级

考题:

setTimeout(() => console.log(4))

new Promise(resolve => {
resolve()
console.log(1)
}).then(()=> {
console.log(3)
}) console.log(2)

考点:

js单线程的运行机制

任务队列

宏任务和微任务的优先级

考点知识点总结见:【本周主题】第一期:JavaScript单线程与异步

解析:

这里涉及到两个比较:

1、同步任务和异步任务的比较、优先级及执行顺序

2、宏任务和微任务的比较、优先级及执行顺序

不懂异步的我可能觉得答案是: 4、2、1、3

不懂微任务的我可能觉得答案是:2、4、1、3

懂异步不懂微任务的我可能觉得答案是:2、1、4、3

但实际答案应该是:1、2、3、4

下面分析一波:

因为setTimeout属于异步任务需要被挂起,所以引擎扫描到他的时候不会执行他,而是将其抛到web APIs里边当做异步任务处理,紧接着向下执行。

遇到new Promise会立即执行,因为这是构造函数创建实例,属于函数调用那一类的代码(new Promise()可以想象成是Promise()函数调用)。所以会读取promise内部代码,读到resolve(),因为resolve()是resolve形参函数的回调,依旧加入异步让其去排任务队列。

紧接着读取下边的console1这一行同步代码,打印出1

因为then需要resolve()调用执行时才会触发,所以也会跳过,

紧接着读到最后一行console2,同步代码,打印出2.

此时,执行栈清空,主线程空闲。就去任务队列里找回调函数来执行,

按照目前分析,此时任务队列里按照顺序加入了如下两个回调,且他们的顺序也应该如下图:

但是实际上,我们忽略了,任务队列中其实是双轨车道:

所以,两个回调函数1号和2号,虽然1号比2号早加入任务队列,但他们在里边的顺序是这样的

而主线程呢,又比较偏向微任务。所以执行宏任务之前,他会先去微任务那里问问,你有没有任务让我执行啊?

此时,resolve()准备就绪,所以主线程把他接走到执行栈执行,打印结果 3

然后主线程又问,你还有任务要我执行吗?

微任务回答:没了。

主线程就说,那好,宏任务轮到你了。

然后最后执行setTimeout的代码,打印4。

2018.11.23 周五面试题:宏任务和微任务的优先级

天啊,每天搜刮合适的面试题都好难啊。请回答下面代码中输出的顺序是什么?

 Promise.resolve().then(()=>{
console.log('Promise1')
setTimeout(()=>{
console.log('setTimeout2')
},0)
}) setTimeout(()=>{
console.log('setTimeout1')
Promise.resolve().then(()=>{
console.log('Promise2')
})
},0)

我果断的做错了。。。

按照我的理解,顺序是这样的:

Promise1 -》 setTimeout2 -》 setTimeout1 -》 Promise2

我做错的原因也就是因为我对考点的不理解和混乱。

考点:

  • 异步任务有哪些及其与同步任务的优先顺序、
  • 任务队列里宏任务和微任务(优先顺序)

解析:

其实正确的答案顺序是

Promise1 -》 setTimeout1 -》 Promise2 -》 setTimeout2

1、异步任务

首先要知道.then()也是异步任务。且then属于微任务。

不信你运行这段代码看看:

 Promise.resolve().then(()=>{
console.log('Promise1')
setTimeout(()=>{
console.log('setTimeout2')
},0)
});
console.log(1);

是不是先输出1,再输入的Promise1。

说明在铁定的同步任务“console.log(1)”之前,Promise.resolve()尽管是先运行,但是遇到then就被挂起到异步线程了。

所以,在上边面试题中,执行完第一行后,现在异步线程里边就是这个情况了:then被扔到了异步线程

》挂起异步任务后,代码接着往下走,到了第8行遇到setTimeout,这铁定的异步,继续挂到异步线程。

》再往下走,没有代码了,主线程空闲。

》于是开始处理任务队列的事件,此时任务队列里还有以下两个待执行任务:分别是then和setTimeout的回调函数。

》优先执行then()回调(第一个异步事件),执行回调函数里边的同步代码,console输出Promise1。

》then回调里边继续向下遇到第3行的setTimeout,挂起

》继续往下,then里边执行完毕,出栈。

》检查没有微任务了(下边没有then了),就处理第二个异步事件,就是第8行的那个定时器,然后执行。console出setTimeout1

》再往下立即执行同步函数Promise.resolve()

》遇到第10行的then,是异步,挂起。

》setTimeout1的回调执行完毕,出栈。

》事件循环前往事件队列找任务。此时事件队列长这样:

》检查有没有微任务,发现第10行的then2的回调,优先执行微任务then2 - 第三个异步事件。输出Promise2。(遇到微任务,即使setTimeout2排在前边也没用)

》继续检查没有微任务了(下边没有then了),没有出栈

》执行第四个异步事件,就是第3行的那个定时器,然后执行。console出setTimeout2。

2018.11.24 周六面试题:一道加大力度的宏任务、微任务题

console.log('begin')
setTimeout(()=>{
console.log('a');
Promise.resolve().then(()=>{
console.log('b');
setTimeout(()=>{
console.log('c');
var arr1 = [];
console.log(arr1 instanceof Array)
});
}).then(()=>{
console.log('d');
});
},0);
console.log('e')

2018.11.25 周日面试题:

console.log('========请按顺序写出以下程序执行结果=======')
console.log('begin')
setTimeout(()=>{
console.log('a');
Promise.resolve().then(()=>{
console.log('b1');
setTimeout(()=>{
console.log('c2');
});
}).then(()=>{
console.log('d2');
});
},0);
console.log('e') var lis = document.getElementsByTagName('li);//假设页面有六个li元素
setTimeout(()=>{
console.log('=================3==============')
console.log('类数组',lis,'转化的第一种方法:');
var arr1 = [],len1 = lis.length;
for(var i = 0; i < len1; i++){
arr1.push(lis[i]);
}
console.log(arr1)
console.log(arr1 instanceof Array)
console.log('类数组',lis,'转化的第二种方法:');
console.log(Array.prototype.slice.call(lis))
console.log(Array.prototype.slice.call(lis) instanceof Array)
});

  

【本周面试题】第2周 - js单线程和异步相关问题的更多相关文章

  1. 【本周主题】第一期:JavaScript单线程与异步

    相信下边这个图一定都不陌生,本周就围绕这张图深入了解下js代码执行时的来龙去脉. 一.JavaScript是单线程的 2018-11-19 21:21:21 周一 js本质是单线程的.这一特性是jav ...

  2. JS单线程和异步

    线程和单线程的概念: 线程:是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同 ...

  3. js的单线程和异步

    前言 说到js的单线程(single threaded)和异步(asynchronous),很多同学不禁会想,这不是自相矛盾么?其实,单线程和异步确实不能同时成为一个语言的特性.js选择了成为单线程的 ...

  4. 从浏览器多进程到JS单线程,JS运行机制的一次系统梳理

    前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...

  5. 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

    前言 来源:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会 ...

  6. JS 单线程

    js单线程阻塞实例setTimeout(function () { while (true) { } }, 1000);setTimeout(function () { alert('end 2'); ...

  7. js的单线程与异步

    一. js 是单线程和异步 1. js 是单线程的,js 的宿主环境(浏览器)是多线程的,实现异步. 2.js是单线程语言,浏览器值分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务, ...

  8. 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?

    https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...

  9. 用故事解析setTimeout和setInterval(内含js单线程和任务队列)

    区别: setTimeout(fn,t): 延迟调用,超过了时间就调用回调函数,返回一个id,使用clearTimeout(id)取消执行. 注意:取消了里面的回调函数就不执行了哦,而不是取消的时候就 ...

随机推荐

  1. java线程安全之并发Queue

    关闭 原 java线程安全之并发Queue(十三) 2017年11月19日 23:40:23 小彬彬~ 阅读数:12092更多 所属专栏: 线程安全    版权声明:本文为博主原创文章,未经博主允许不 ...

  2. 《es6标准入门》chapter11中关于Proxy的一个错误例子的纠正

    在原书第二版的p120,这里有一个使用Proxy实现管道化调用的例子,想法很好,但是代码有问题,下面是更正之后的代码. 由于我是在node环境下运行,所以我把几个全局函数定义到global内了,如果是 ...

  3. 未解决:长字符串含…

    用reduce拼了一个超长sql语句,大约65000字符,运行通不过,报错: OperationalError: (1054, "Unknown column 'nan' in 'field ...

  4. postgresql 函数获取多个字段的数字大小值

    1.GREATEST(n1,n2,n3,..........) 获取最大值 testdb=#SELECT GREATEST(,,,,,,,,,); +------------------------- ...

  5. angularjs图片上传和预览 - ng-file-upload

    ng-file-upload ajax上传文件 官方demo地址 安装 bower install ng-file-upload-shim --save(for non html5 suppport) ...

  6. 结巴分词和自然语言处理HanLP处理手记

    手记实用系列文章: 1 结巴分词和自然语言处理HanLP处理手记 2 Python中文语料批量预处理手记 3 自然语言处理手记 4 Python中调用自然语言处理工具HanLP手记 5 Python中 ...

  7. Notes 和 Domino 已知限制

    Notes 和 Domino 已知限制 功能测试 限制数据库的最大大小是多少? 最大的 OS 文件大小限制 -(最大为 64GB)文本域的最大大小是多少? 15KB(存储):15KB,显示在视图列中R ...

  8. ant+svn+tomcat实现自动构建

    前段时间用做了一个简单的web api服务,在调试的过程中感觉到手动发布实在是效率低而且容易出错,于是花点时间搞了一下ant+svn+tomcat的自动构建,效果不错,今天拿出来分享一下. 准备工作 ...

  9. aaronyang的百度地图API之LBS云[把数据丰富显示1/3]

    中国的IT 需要无私分享和贡献的人,一起努力 本篇博客来自地址:http://www.cnblogs.com/AaronYang/p/3673933.html,请支持原创,未经允许不许转载 一.第一步 ...

  10. Activity标题(title)的显示和隐藏

    开发Android应用程序,我们总会遇到Activity的title把显示的内容遮挡了一部分.如果能把它去掉,我们的应用界面就会变得更加简洁,那该多好.下面有两种方法可以去掉: (方法一):通过一句J ...