同步 异步
你去商城买东西,你看上了一款手机,能和店家说你一个这款手机,他就去仓库拿货,你得在店里等着,不能离开,这叫做同步。现在你买手机赶时髦直接去京东下单,下单完成后你就可用做其他时间(追剧、打王者、lol)等货到了去签收就ok了.这就叫异步。
异步场景
- 定时任务:setTimeout, setInterval
- 网络请求:前端向后台请求API数据,图片加载
- 事件监听:addEventListener
为什么js是单线程?
js作为主要运行在浏览器的脚本语言,js主要用途之一是操作DOM。
例子,如果js同时有两个线程,同时对同一个dom进行操作,这时浏览器应该听哪个线程的,如何判断优先级?
为了避免这种问题,js必须是一门单线程语言,并且在未来这个特点也不会改变。
事件循环 Event loop
同步代码不受事件循环影响,不会进入callback Queue
执行栈 与 任务队列
- 主线程 规定现在执行执行栈中的哪个事件。
即主线程会不停的从执行栈中读取事件,会执行完所有栈中的同步代码。
当遇到一个异步事件后,并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不同的队列中,我们称之为任务队列(Task Queue)。
当主线程将执行栈中所有的代码执行完之后,主线程将会去查看任务队列是否有任务。如果有,那么主线程会依次执行那些任务队列中的回调函数。
- 总结:js 异步执行的运行机制
1. 所有任务都在主线程上执行,形成一个执行栈。
2. 主线程之外,还存在一个"任务队列"。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列"。那些对应的异步任务,结束等待状态,进入执行栈并开始执行。
4. 主线程不断重复上面的第三步。
-
执行栈 事件发生时会进入执行栈中,等待主线程读取,遵循先进先出原则。
-
任务列表
- 宏任务 :setTimeout、setInterval
- 微任务 :Promise
-
事件循环(Event Loop),每一次循环称为 tick, 每一次tick的任务如下:
- 执行栈选择最先进入队列的宏任务,如果有则执行
- 检查是否存在 Microtask,如果存在则不停的执行,直至清空 microtask 队列
- 更新render(每一次事件循环,浏览器都可能会去更新渲染)
- 重复以上步骤
宏任务 > 所有微任务 > 宏任务
补充内容:Promise
状态变化
new Promise() 返回两种结果
- 初始
- status: "pending"
- result: undefined
- 初始-resolve("done")→ 成功
- status: "fullfilled"
- result: "done"
- 初始-resolve("error")→ 失败
- status: "rejected"
- result: "error"
new Promise(()=>{...})
.then((response)=>{ // 成功 call API
console.log(response);
})
.catch(err => console.log(err)); //失败 call API
Axios
- 概念
一个基于promise的第三方HTTP库,内容使用的是XMLHttpRequest 支持nodejs和浏览器环境,兼容性好
- 使用
import axios from "axios"
axios.get(url).then((response)=>{
console.log(response.data); //直接拿到data
})