仅一篇文章带你彻底了解js执行机制

仅用一篇文章带你彻底了解js执行机制顺序,看完没收获你来揍我!


前言

每次写代码的时候,有些点老是不明白执行的先后顺序,虽然有的时候无关紧要

现在让我们在正文开始之前,做道题,试试自己是否真正掌握了js执行机制!

题目:

async function async1() {
    
    
	console.log("async1 start");
	await async2();
	console.log("async1 end");
    }
async function async2() {
    
    
        console.log("async2");
    }
    console.log("js start");
    setTimeout(function () {
    
    
        console.log("timeout");
    }, 0);
    async1();
    new Promise(function (resolve) {
    
    
        console.log("promise");
        resolve();
    }).then(function () {
    
    
        console.log("then");
    });
    console.log("js end");

正确答案:

js start
async1 start
async2
promise
js end
async1 end
then
timeout

以下是本篇文章正文内容,和作者一起探索吧!

一、JS任务和事件循环

想必大家都曾听过Js是一门单线程语言,每一个时刻只能执行一个任务(JS引擎在执行任务时,是一个一个执行的,如果有多个任务,则后面的任务只能等待)

1.1JS任务

如果js的任务都是同步任务的话,那么遇到定时器、网络请求等这类型需要延时执行的任务,页面可能会瘫痪,需要暂停下来等待这些需要很长时间才能执行完毕的任务,用户体验就很烂,所以我们需要引入异步任务,让这些执行会很长时间的代码都往后稍稍
同步任务:同步任务不需要进行等待可立即看到执行结果,比如console
异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求

1.2事件循环

当有任务时:
从最先进入的任务开始执行(第1步)
没有其他任务时:
休眠直到出现任务,然后重新转到第 1 步

二、JS执行机制 同步任务和异步任务

2.1JS执行机制原理

js代码开始执行后,主线程执行栈中会把任务分为两类(同步任务和异步任务
主线程执行栈优先执行同步任务异步任务会被放入特定的处理程序中,满足条件后,被放到消息(任务/事件)队列中,主线程执行栈中所有的同步任务执行完毕之后通过事件循环去消息(任务/事件)队列中,将优先满足条件的程序放入主线程执行栈中执行。事件循环,周而复始。

文字都是生硬难理解的,接下来我放两张经典的图片,配合讲解一个具体的例子!

在这里插入图片描述
在这里插入图片描述

2.2小试牛刀题目(有讲解)

    setTimeout(() => {
    
    
        console.log('定时器开始啦!定时0秒钟,大家是不是觉得我会立马执行!');
    }, 0);
    console.log('你们猜错啦!同步任务优先执行!');
      setTimeout(() => {
    
    
        console.log('呜呜呜,我比上一个定时器多延时了一点,在所有同步任务都执行完后,没有优先满足条件,我要最后执行了');
    }, 0.1);

代码从上往下执行,先碰到了定时器,主线程执行栈认定它为异步任务,于是把它丢给了Event Table(异步任务特定的处理程序),并且开始计时0秒钟,当0秒钟到了以后就注册定时器的回调函数,并且把函数里的内容放入消息队列当中,当所有的同步代码都执行完后,才会执行消息队列中的内容,异步任务谁先满足条件,谁就优先放入消息队列中,并且优先执行
所以这里的执行顺序是
1.碰到定时器 丢到Event Table,开始计时,满足条件之后再交给消息队列
2.碰到同步任务console,直接出结果 控制台打印
3. 碰到定时器 丢到Event Table,开始计时,满足条件之后再交给消息队列
4. 所有同步任务执行完毕,去消息队列中找有没有满足条件的程序,把它放入主线程执行栈中执行
5. 第一个定时器先满足条件优先执行,第二个随后执行
6. 检测到任务队列都已执行完成,代码执行结束

你们猜错啦!同步任务优先执行!
定时器开始啦!定时0秒钟,大家是不是觉得我会立马执行!
呜呜呜,我比上一个定时器多延时了一点,在所有同步任务都执行完后,没有优先满足条件,我要最后执行了

看到这相信你已经差不多明白了!但还是差了一些特殊的东西!临门一脚!

3.异步任务中的宏任务和微任务

3.1微任务和宏任务概念讲解

以上说了同步任务和异步任务是如何执行的,但其实异步任务中还要细分为宏任务和微任务微任务的执行顺序在宏任务之前,咱接着讲解!
在ES3 以及以前的版本中,JavaScript本身没有发起异步请求的能力,也就没有微任务的存在,(以前都是由宿主(node、浏览器)发起的)在ES5之后,JavaScript引入了Promise,不需要浏览器,JavaScript引擎自身也能够发起异步任务了
Tick会触发浏览器渲染,Promise不会触发,所以Promis更加轻量级
(在事件循环中,每进行一次循环操作称为 Tick)
微任务和宏任务的关系就像,今天班主任在班上用嗓门宣布今天放假,和校长在广播里宣布放假一样,宏任务牵扯的资源更多,会引发浏览器重绘,而微任务更加轻量级,微任务的执行顺序在同步任务后,宏任务之前
在这里插入图片描述
常用的微任务也就Promise

4.微任务中的Promise、async、await

4.1 async await执行顺序(题目以及讲解)

Promise是处理异步操作的一种方法(典型案例就是回调地狱),而大家常用的async/await 是基于 Promise 的一种语法糖,它提供了一种更直观和同步化的方式来编写异步代码,接着我们来说说Promise、async、await的执行顺序
async function a (){} async顾明思议就是异步的意思,但是函数被调用时,代码会正常立即执行(就是正常的同步任务),但是当碰到await关键词时,await后面跟着的代码会立即执行,但是await下一行的语句会作为微任务加入到微任务队列中,上代码!

async function getPromise() {
    
    
    return '我是getPromise函数';
}
console.log(1);
async function fn() {
    
    
    console.log(2);
    let str = await getPromise();
    console.log(str);
    console.log(4);
}
fn();
setTimeout(() => {
    
    
    console.log('我是一个大大的宏任务,我执行的不如微任务快');
}, 0);
console.log(3);

1.同步代码console.log(1)执行
2.async修饰的函数正常执行,console.log(2)
3.遇到了await,await后面的代码立即执行,剩下的被当做微任务丢给了异步处理程序,所以打印str和4的代码被丢进了微任务队列里
4.定时器定时0秒,丢进宏任务里
5.打印3
6.同步任务解决完毕,开始去消息队列里找满足条件的任务,优先完成微任务,
发现有微任务,打印’我是getPromise函数’,打印4
7.微任务执行完,轮到宏任务,打印’我是一个大大的宏任务,我执行的不如微任务快’
答案:
1
2
3
我是getPromise函数
4
我是一个大大的宏任务,我执行的不如微任务快

4.2 Promise执行顺序(题目以及讲解)

最后一个点啦!坚持就是胜利!
那就是promise的执行顺序,promise是这样的,在new 创建实例对象时当做参数传入的函数,是立即执行的,但是后面的then会被加入到微任务队列。

console.log(1);
new Promise((resolve, reject) => {
    
    
   console.log('同学们,我也是立即执行的!');
   resolve('then中的代码是微任务!')
}).then(res => {
    
    
    console.log(res);
})
console.log(2);

答案:
1
同学们,我也是立即执行的!
2
then中的代码是微任务!
(大家如果对promise不了解,建议先去重新学习下!)

大结局(开篇题目讲解)

看到这相信大家一定学有所获,跟着我一起来复盘下吧!

async function async1() {
    
    
	console.log("async1 start");
	await async2();
	console.log("async1 end");
    }
async function async2() {
    
    
        console.log("async2");
    }
    console.log("js start");
    setTimeout(function () {
    
    
        console.log("timeout");
    }, 0);
    async1();
    new Promise(function (resolve) {
    
    
        console.log("promise");
        resolve();
    }).then(function () {
    
    
        console.log("then");
    });
    console.log("js end");

1.打印同步代码 console.log(“js start”)
2.开启定时器,放到异步处理程序的宏任务队列里
3.立即执行async1 的代码,console.log(“async1 start”);
4.碰到了await,await后紧跟着的内容立即执行,async2 函数被执行,console.log(“async2”);
5.async1 剩下的内容交给了微任务队列
6.promise function里的内容立即执行, console.log(“promise”);
7.then里的内容加入到微任务队列中
8.打印同步代码 console.log(“js end”);
9.所有同步代码执行完毕,检查是否有异步任务,优先执行微任务
10.依次执行微任务,console.log(“async1 end”);
console.log(“then”);
11.微任务队列为空,开始执行宏任务队列, console.log(“timeout”);
12.检测到任务队列都已执行完成,代码执行结束
答案

    //  js start
    //  async1 start
    //  async2
    //  promise
    //  js end
    //  async1 end
    //  then
    //  timeout

总结

感谢大家的观看,这么多内容也是本人抽空花了零零碎碎两天的时间学习并且和大家分享的,希望大家多多支持前端百草阁,咱们共同进步!
有问题的大家私信我,每天都会回复

猜你喜欢

转载自blog.csdn.net/m0_57524265/article/details/131013978