深入浅出JS 您所在的位置:网站首页 js事件循环面试题 深入浅出JS

深入浅出JS

2024-06-14 23:57| 来源: 网络整理| 查看: 265

1. JS中为什么要有事件循环

由于JS是单线程的,一些异步问题通常交由别的线程来处理,处理之后将结果加入事件队列,当JS线程代码执行完,会去事件队列中取事件,到JS线程继续执行,直到事件队列被清空: JS线程——》其他线程——》事件队列 这三者构成了闭环,形成了事件循环

2. 浏览器中的事件循环

在这里插入图片描述

任务队列:

宏任务队列:setTimeout; setInterval; ajax; dom事件点击等微任务队列:Promise.then; queueMicrotask

优先级:

微任务队列>宏任务队列同一个队列内部:先进先出 注意:async函数会像普通函数一样正常执行,如果函数里面有await关键字,那么await后面表达式返回的是一个Promise对象,Promise.then是微任务 题目1

async-await promise.then queueMicrotask setTimeout

async function async1 () { console.log('async1 start') await async2(); console.log('async1 end'); } async function async2 () { console.log('async2') } console.log('script start') setTimeout(function () { console.log('setTimeout2') }, 10) setTimeout(function () { console.log('setTimeout1') }, 0) async1(); new Promise (function (resolve) { console.log('promise1') resolve(); }).then (function () { console.log('promise2') }) queueMicrotask(()=>{ console.log('queueMicrotask') }) console.log('script end') /** * script start * async1 start * async2 * promise1 * script end * async1 end * promise2 * queueMicrotask * setTimeout1 * setTimeout1 */ await后面表达式属于上一个代码块,表达式内容会被立即执行,返回promise.then会加入微任务队列setTimeout( ()=>{},10):回调函数10ms后才被加入宏任务队列 题目2 new Promise((resolve) => { resolve(); }) .then(() => { new Promise((resolve) => { console.log(000); resolve(); }) .then(() => { console.log(111); }) .then(() => { console.log(222); }); // return undefined; }) .then(() => { console.log(333); }); /** * 000 * 111 * 333 * 222 */ 执行完console.log(000)之后,就将之后的then函数塞入微任务队列然后执行return undefined;然后将console.log(333)的then塞入微任务队列这时取出console.log(111)执行完后,将console.log(222)加入任务队列的队尾巴所以333在222之前输出 3. Node中的事件循环

浏览器中的事件循环是根据HTML5定义的规范来实现的,不同的浏览器可能会有不同的实现,而Node中是由libuv实现的,libuv是一个多平台的专注于异步IO的库,主要维护了一个EventLoop和worker threads(线程池) 在这里插入图片描述 事件循环像是一个桥梁,是连接着应用程序的JavaScript和系统调用之间的通道

无论是文件IO、数据库、网络IO、定时器、子进程,在完成对应的操作后,都会将对应的结果和回调函数放到事件循环(任务队列)中;事件循环会不断的从任务队列中取出对应的事件(回调函数)来执行; Node中的事件循环 定时器(Timers):执行setTimeout() 和 setInterval() 的回调函数。待定回调(Pending Callback):对某些系统操作(如TCP错误类型)执行回调idle, prepare:仅系统内部使用。轮询(Poll):检索新的 I/O 事件;执行与 I/O 相关的回调;检测(check):setImmediate() 回调函数在这里执行。关闭的回调函数:一些关闭的回调函数,如:socket.on(‘close’, …) Node中任务队列

微任务队列

next tick queue:process.nextTick;other queue:Promise的then回调、queueMicrotask;

宏任务队列:

timer queue:setTimeout、setInterval;poll queue:IO事件;check queue:setImmediate;close queue:close事件

优先级:

微任务>宏任务微任务中:process.nextTick队列 > 其他队列宏任务中:setTimeout,setInterval队列 > IO队列 >setImmediate队列>close队列每个队列中,先进先出 与浏览器区别 多了方法: procress.nextTick, setImmediate微任务中有两种队列,宏任务中有四种队列,注意队列的优先级关系Node中事件循环,不仅包括宏任务,还有一些其他pending callbak和idle,prepare等 题目1 async function async1() { console.log('async1 start') await async2() console.log('async1 end') } async function async2() { console.log('async2') } console.log('script start') // 300ms后加入事件队列 setTimeout(function () { console.log('setTimeout2') }, 300) setImmediate(() => console.log('setImmediate')); setTimeout(function () { console.log('setTimeout0') }, 0) process.nextTick(() => console.log('nextTick1')); async1(); process.nextTick(() => console.log('nextTick2')); new Promise(function (resolve) { console.log('promise1') resolve(); console.log('promise2') }).then(function () { console.log('promise3') }) console.log('script end') /** * script start * async1 start * async2 * promise1 * promise2 * script end * nextTick1 * nextTick2 * async1 end * promise3 * setTimeout0 * setImmediate * setTimeout2 */ process.nextTick是先于promise.then执行resolve()将then的回调函数加入微任务队列中,之后的语句console.log(‘promise2’)依然会立即执行setTimeout队列的优先级高于setImmediate,如果前者队列中有值,会先清空


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有