无论你是新手还是老手,无论你是在面试工作还是在做日常的开发工作,我们经常会遇到这样的情况:给定几行代码,我们需要知道它的输出内容和顺序。 因为它是一种单线程语言,所以我们可以得出结论:
按照语句出现的顺序执行
看到这里,读者要打人了:难道我不知道js是一行一行执行的吗? 你需要说什么? 不要不耐烦,因为js是一行一行执行的,所以我们认为js是这样的:
let a = '1';
console.log(a);
let b = '2';
console.log(b);
但实际上js是这样的:
setTimeout(function(){
console.log('定时器开始啦')
});
new Promise(function(resolve){
console.log('马上执行for循环啦');
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log('执行then函数啦')
});
console.log('代码执行结束');
按照js是按照语句出现的先后顺序执行的理念,我自信的记下输出结果:
//"定时器开始啦"
//"马上执行for循环啦"
//"执行then函数啦"
//"代码执行结束"
上去验证,结果完全错了,瞬间懵了。 是否逐行执行约定?
我们真的要把执行机制搞清楚。
关于
它是一种单线程语言。 Web-是在最新的HTML5中提出的,但单线程核心并没有改变。
所以所有版本的“多线程”都是单线程模拟的,所有多线程都是纸老虎!
事件循环
由于js是单线程的,就好像银行只有一个窗口。 客户需要排队办理业务。 同样,js任务也要一个一个执行。
如果一个任务花费的时间太长,那么后一个任务也必须等待。 那么问题来了,如果我们想浏览新闻,但是新闻中包含的超高清图片加载的很慢js页面加载完成后执行,我们的网页是不是应该一直卡到图片全部显示出来?
所以聪明的程序员将任务分为两类:
当我们打开网站时,网页的渲染过程是很多同步的工作,比如页面骨架和页面元素的渲染。 而加载图片、音乐等占用资源多、耗时长的任务,则属于异步任务。
这部分有严格的文字定义,但本文的目的是以最小的学习成本彻底理解执行机制,所以我们用一张图来说明:
如果地图中要表达的内容用文字表达:
我们不禁要问,我们怎么知道主线程执行栈是空的呢? js引擎有一个进程,它会不断的检查主线程执行栈是否为空。 一旦为空,就会去Event Queue中查看是否有等待调用的函数。
说了这么多文字,直接写一段代码更直接:
let data = [];
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('发送成功!');
}
})
console.log('代码执行结束');
上面是一段简单的ajax请求代码:
相信通过上面的文字和代码,你对js的执行顺序有了初步的了解。 接下来,让我们研究高级主题:。
爱与恨
著名的就不用多说了。 大家对他的第一印象就是异步执行可以延时。 我们经常通过这种方式来实现延迟3秒:
setTimeout(() => {
console.log('延时3秒');
},3000)
渐渐地,用到的地方越来越多,问题也随之而来。 有的时候明明写的是延时3秒,但是函数实际是5、6秒后才执行。 怎么了?
我们先来看一个例子:
setTimeout(() => {
task();
},3000)
console.log('执行console');
根据我们之前的结论,是异步的,应该先执行.log的同步任务,所以我们的结论是:
//执行console
//task()
验证一下,结果是正确的!
然后我们修改之前的代码:
setTimeout(() => {
task()
},3000)
sleep(10000000)
乍一看差不多,但是当我们执行这段代码的时候,我们发现控制台执行task()需要3秒多的时间。 约定的延迟为 3 秒。 为什么现在需要这么长时间? ?
这时候我们需要重新理解定义。 先来说说上面代码是如何执行的:
上面的流程完成后,我们知道这个函数是在指定的时间后,将待执行的任务(本例中的task())添加到Event Queue中,由于是单线程的待执行任务其一,如果之前的任务耗时过长,则只能等待,导致真正的延迟时间远远超过3秒。
我们也经常遇到类似(fn,0)这样的代码,0秒后执行是什么意思? 可以立即执行吗?
答案是不。 (fn,0)的含义是指定一个任务在主线程最早可用的空闲时间执行,也就是说不需要等待很多秒,只要主线程执行完所有的同步堆栈中的任务。 完成,栈为空时立即执行。 例如:
//代码1
console.log('先执行这里');
setTimeout(() => {
console.log('执行啦')
},0);
//代码2
console.log('先执行这里');
setTimeout(() => {
console.log('执行啦')
},3000);
代码1的输出是:
//先执行这里
//执行啦
代码2的输出是:
//先执行这里
// ... 3s later
// 执行啦
我要补充的是,即使主线程是空的,0毫秒其实也是不可达的。 根据 HTML 标准,最小值为 4 毫秒。 感兴趣的同学可以自行学习。
恨爱
说完以上,当然不能少了它的孪生兄弟。 它们很相似,只是后者是循环执行。 对于执行顺序,注册的函数会按指定的时间间隔放入Event Queue,如果之前的任务耗时太长,也需要等待。
唯一需要注意的是,对于(fn, ms),我们已经知道fn不会每隔ms秒执行一次,而是每隔ms秒就会进入Event Queue。 一旦回调函数fn的执行时间超过延迟时间ms,那么就完全没有时间间隔了。 请仔细阅读这句话。
和。()
传统的定时器我们已经研究过了,接下来我们探讨一下用.()的性能。
.()的定义和作用类似于node.js版本中的"",在事件循环的下一个循环中调用回调函数。
让我们进入正题。 除了广义的同步任务和异步任务,我们还有更细化的任务定义:
不同类型的任务会进入对应的Event Queue,例如,会进入同一个Event Queue。
事件循环的顺序决定了js代码的执行顺序。 进入整体代码(宏任务)后js页面加载完成后执行,开始第一个循环。 然后执行所有微任务。 然后再从宏任务开始,找到其中一个要执行的任务队列,然后执行所有的微任务。
听起来有点绕,我们用文章开头的一段代码来说明一下:
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
事件循环、宏任务和微任务的关系如图所示:
下面来分析一段比较复杂的代码,看看你是否真的掌握了js的执行机制:
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
第一轮事件循环流程分析如下:
好了,第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。那么第二轮时间循环从宏任务开始:
整个代码,一共三个事件循环,完整的输出是1,7,6,8,2,4,3,5,9,11,10,12。
请注意node环境下的事件监听依赖libuv和前端环境不完全一样,可能输出顺序不对。
写在最后
(1)异步js
一开始我们就说它是单线程语言。 不管新框架新语法糖实现了什么样的所谓异步,其实都是通过同步的方式模拟出来的。 牢牢掌握单线程语言非常重要。
(2) 事件循环Event Loop
事件循环是js实现异步的一种方法,也是js的执行机制。
(3) 执行及运作
执行和操作之间有很大的区别。 在不同的环境下,比如node、、Ringo等,执行方式不同。 操作多是指分析引擎,是统一的。
(4)
微任务和宏任务的种类很多,比如等等,执行上有共同点,有兴趣的同学可以自行学习。
(5) 最后最后
牢牢抓住两个基本点,专心认真学习,早日实现成为前端高手的伟大梦想!
- 结尾 -
》《面试官都在用的题库,快来看看》
女忍手游攻略:调教女忍快速提升战力!
2023-04-29 11:01:24 7502玩转烟雨江湖太乙教学攻略:技能详解,教你轻松驾驭江湖!
2023-04-29 11:01:24 800玩转问道手游神魂系统,最新攻略助你获得最强神魂!
2023-04-29 11:01:24 743三国志战略版qq账号能转移吗 qq登录解绑方法
2023-04-29 11:01:24 736玩如龙7手游必备攻略,轻松打败对手!
2023-04-29 11:01:24 662斗破苍穹手游:解锁伙伴攻略大揭秘!
2023-04-29 11:01:24 659三国竞技场自走棋攻略 DOTA2三国竞技场自走棋阵容推荐(附武将羁绊图鉴)
2023-04-29 11:01:24 645犯罪大师追踪怪盗答案 侦探事务所周四4星委托任务答案
2023-04-29 11:01:24 582gta5捏脸数据女神(含男女二次元)2021最新教程
2023-04-29 11:01:24 575百变大侦探失控时空攻略完整版
2023-04-29 11:01:24 567