事件循环与Http缓存
事件循环机制
- 同步任务:按顺序逐行执行的代码,需原地等待结果后才继续向下执行
- 异步任务:调用后耗时,不阻塞代码继续执行,在将来完成后触发一个回调函数
组成
- 调用栈:存放正在执行的函数调用,顺序为先进后出。
- 任务队列:存储异步函数,包括
setTimeout、setInterval、I/O事件、UI渲染 - 微任务队列:存储微任务,如Promise的
.then .catch .finally
流程
- 执行一次宏任务,将同步代码存入调用栈并执行;
- 处理微任务,直到队列清空;
- 渲染页面;
- 取一个宏任务执行,重复上述步骤
注意
- 微任务优先级高于宏任务
- 每个宏任务执行后会清空微任务队列
- 同类型任务按入队顺序执行
示例
1 | console.log('1'); |
- 先执行同步任务,输出1,
setTimeout为宏任务,进入任务队列,asyncFuncA进入队列输出二,执行await后的表达式并将后续代码注册进微任务队列,await后的表达式.then为微任务并进入微任务队列,asyncFuncA离开队列,asyncFuncB进入队列输出5,await后的asyncFuncNested函数进入队列,输出7并将.then注册进微任务队列,asyncFuncNested,asyncFunB离开队列,输出13,同步代码执行完毕,接下来处理微任务 - 先是
asyncFuncA里await后的.then,输出3,之后执行await后续代码输出4,然后是asyncFuncB里asyncFuncNested里的微任务,输出8,接着执行asyncFuncB里await后续的代码,输出6,微任务执行完毕,接下来处理下一个宏任务 - 执行setTimeout里的代码,输出9,.then进入微任务队列,
setTimeout进入任务队列,同步代码执行完毕,执行微任务,输出10,取下一个宏任务,输出12 - 注意:async函数中await后的表达式先执行,再将后续代码注册进微任务队列。
HTTP缓存机制
分类
- 强制缓存:在有效期内,客户端直接使用本地缓存,不向服务器发送请求
- 协商缓存:强制缓存过期后,客户端携带上次响应提供的校验标识(如
ETag或Last-Modified)向服务器询问资源是否变化
关键响应头
Expires:强制缓存,示例:Expires: Wed, 21 Oct 2025 07:28:00 GMT,使用GMT格式的绝对时间,问题是客户端与服务端时间不一致会导致缓存不准确。Cache-Control:强制缓存,常见指令:max-age=3600(单位为秒)、no-cache(不使用强制缓存)、no-store(禁止缓存)、private``public(只有浏览器可缓存与浏览器、服务器和代理服务器均可缓存)。Last-Modified:协商缓存,资源的最后修改时间,之后客户端会发送值相同的If-Modified-Since,请求时与最后请求时间对比并确定是否继续使用缓存,问题是该响应头以秒级别记录,若资源在一秒内发送变化则无法感知到。ETag:协商缓存,首次请求后响应头返回ETag,值为服务器为文件生成的唯一标识,之后请求客户端会发送值为ETag的If-None-Match,将该值与服务器资源的ETag对比。
流程
- 强制缓存:客户端拿到资源后记录本地缓存的
max-age或Expires,下次请求时,若未过期则直接读取本地缓存,不发送网络请求。 - 协商缓存:强制缓存过期后,客户端带上
If-None-Match或If-Modified-Since向服务器发送请求。若未修改,返回304,继续使用本地缓存,且会更新本次的缓存头;若已修改,返回200和新的资源以及新的缓存头。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 MNCLI!
评论











