# 一、async 和 async
# 1、Async 函数
该函数返回的是一个 promise 对象。
async function Fn() {
// return 1
// throw 2
// return Promise.resolve(3)
return Promise.reject(4)
}
console.log(Fn())
Fn()
.then((res) => {
console.log('onFulfillment', res)
})
.catch((err) => {
console.log('onRejection', err)
})
观察发现,它和我们前面学到 Promise.then()有很多相似之处:
new Promise((resolve, reject) => {
// resolve(1)
reject(2)
})
.then((res) => {
console.log('onFulfillment', res)
})
.catch((err) => {
console.log('onRejection', err)
})
那使用 async 函数有什么用处呢?
当它结合后面的 await 时,就知道它有多么优秀了。
# 2、await 操作符
提示
await 必须写在 async 函数中,但 async 函数中可以没有 await
在传统的 Promise 中,如果我们仅仅想要回去成功回调的返回值,有没有更加简洁的写法。
- 以前
new Promise((resolve, reject) => {
resolve('success')
}).then((res) => {
console.log('操作成功:', res)
})
- 现在
await 后面通常跟的是一个 Promise 对象
async function fn1() {
const res = await Promise.resolve(4)
}
fn1()
那怎么处理,失败回调呢?
async function fn1() {
try {
const res = await Promise.reject(4)
} catch (err) {
console.log(err)
}
}
fn1()
# 3、Async / await ✨
现在我们已经知道了 async
函数返回的是一个 Promise,await
后面可以跟一个 Promise 的成功回调结果。
现在我们综合一下看看:
async function fn1() {
const res = await Promise.resolve(4)
return res
}
fn1()
.then((res) => {
console.log('onFulfillment', res)
})
.catch((err) => {
console.log('onRejection', err)
})
利用 async 和 await 各自的特点,我们貌似达到了将异步任务放在 async 函数中同步执行的效果 🤔。
代码体验
async function test() {
var res = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data')
console.log('1111') // ①
})
})
console.log('2222') // ②
return res // ③
}
test()
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
执行结果:
1111
2222
data
- 解决回调地狱
async function fn1() {
const res1 = await Promise.resolve(1)
const res2 = await Promise.resolve(4 + res1)
console.log('---- | ---')
return res2
}
console.log(fn1())
// Promise {<pending>}
// ---- | ---
# 二、事件循环机制(EventLoop)
JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。
但是他的运行环境浏览器确不是单线程的。
# 1、执行流程
为了防止某个耗时任务导致程序假死的问题,JavaScript 包待执行任务分为:异步任务(非耗时) 和 同步任务(耗时)。
同步代码交给 浏览器的 JS 引擎执行,异步代码先交给宿主环境(浏览器/Node)相应的 Web APIs 模块管理执行。
在宿主环境中已经完成的异步任务会被加入到消息队列中等待执行。
消息队列中如果存在微任务队列,则该任务队列会被优先放到栈中执行。
JavaScript 主线程从“消息队列”中读取异步任务的回调函数,放到执行栈中依次执行。这种不断循环运行的机制又被称为 EventLoop(事件循环)
注意:Promise 本身是同步的,但是 then 和 catch 是异步的
# 2、经典面试题
// 宏任务
setTimeout(function () {
console.log('1')
})
new Promise(function (resolve) {
console.log('2')
resolve()
}).then(function () {
// 微任务
console.log('3')
})
console.log('4')
// 执行结果为: 2431
# 3、ajax 作用域 🎈
下面简单的描述一个问题:
// 全局作用域
let data = {}
// 发起Ajax请求
fetch('https://jsonplaceholder.typicode.com/users/1')
.then((res) => res.json())
.then((res) => {
data = res
})
console.log(data) // {}
那如何解决呢?
方案 1:XHR 同步请求
let data = {}
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://jsonplaceholder.typicode.com/users/1', false) // 同步请求
xhr.send()
if (/^2\d{2|$/.test(xhr.status)) {
data = JSON.parse(xhr.responseText)
}
console.log(data) // {id: 1, name: 'Leanne Graham', username: 'Bret', email: '[email protected]', address: {…}, …}
方案 2: async / await 异步控制
async function demo() {
let data = {}
data = await fetch('https://jsonplaceholder.typicode.com/users/1').then((res) => res.json())
console.log(data) // {id: 1, name: 'Leanne Graham', username: 'Bret', email: '[email protected]', address: {…}, …}
}
demo()