JS基础-三座大山之三一异步(2)
了解了异步的基本原理之后,我们学习一下Promise相关知识,如果你还没有了解异步基本原理请点击 JS基础-三座大山之三一异步(1)进行学习.介绍完Promise后本篇文章将列举几个异步相关的练习题进行讲解
带着以下几个问题开始学习吧
- promise
- async-await
- Promise有哪三种状态
- Promise then和catch的连接
- Promise和setTimeout的顺序
- async/await的顺序问题
1. Promise
Promise 是 JavaScript 中处理异步操作的核心机制,它解决了传统回调函数嵌套("回调地狱")的问题,让异步代码更易读、更易维护。
1.1 Promise的3种状态
-
Pending(等待中):初始状态,既未完成也未拒绝
-
Fulfilled(已兑现):异步操作成功完成,调用 resolve() 后进入此状态
-
Rejected(已拒绝):异步操作失败,调用 reject() 后进入此状态
状态一旦改变就不可逆
(Pending → Fulfilled 或 Pending → Rejected)
1.2 使用一下Promise
1. 创建 Promise
const myPromise = new Promise((resolve, reject) => {
// 异步操作(例如 API 请求、定时器等)
const success = true; // 模拟操作结果
if (success) {
resolve("操作成功!"); // 状态变为 Fulfilled
} else {
reject("操作失败!"); // 状态变为 Rejected
}
});
2. 使用 Promise:.then()、.catch()、.finally()
myPromise
.then((result) => {
console.log(result); // "操作成功!"(处理成功状态)
})
.catch((error) => {
console.error(error); // "操作失败!"(处理失败状态)
})
.finally(() => {
console.log("无论成败都会执行"); // 清理操作(可选)
});
3. Promise 链式调用
Promise 支持链式操作,避免回调嵌套:
fetchData()
.then(processData) // 第一步处理数据
.then(saveData) // 第二步保存数据
.catch(handleError); // 统一处理所有错误
4. 静态方法
- Promise.all([p1, p2, p3])
所有 Promise 全部成功时返回结果数组,任意失败立即抛出错误。
Promise.all([promise1, promise2])
.then(([res1, res2]) => console.log(res1, res2));
- Promise.race([p1, p2])
返回最先改变状态的 Promise 结果(无论成功/失败)。
Promise.race([apiCall, timeoutPromise])
.then(firstResult => console.log(firstResult));
- Promise.allSettled([p1, p2])
等待所有 Promise 完成(无论成败),返回状态和结果数组。
Promise.allSettled([p1, p2]).then(results => {
results.forEach(({status, value, reason}) => {
if (status === 'fulfilled') console.log(value);
else console.error(reason);
});
});
- Promise.resolve() / Promise.reject()
快速创建成功/失败的 Promise。
1.3 状态的表现
-
pending状态,不会触发then和catch
-
resolved状态,会触发后续的then回调函数
-
rejected状态,会触发后续的catch回调函数
-
resolve只会触发then的回调,不会触发catch
-
reject只会触发catch的回调,不会触发then
const p = new Promise((resolve,reject)=>{
})
console.log(p) // pending
const p1 = new Promise((resolve,reject)=>{
resolve()
})
console.log(p1) // resolved
const p2 = new Promise((resolve,reject)=>{
reject()
})
console.log(p2) // rejected
const p3 = Promise.resolve(100) // resolved
const p4 = Promise.reject(200) // resolved
const p = new Promise((resolve,reject)=>{
})
console.log(p) // pending
const p1 = new Promise((resolve,reject)=>{
resolve()
})
console.log(p1) // resolved
const p2 = new Promise((resolve,reject)=>{
reject()
})
console.log(p2) // rejected
const p3 = Promise.resolve(100) // resolved
const p4 = Promise.reject(200) // resolved
p3.then(data=>{
})
p4.catch(err=>{
})
1.3 then 和 catch改变状态
- then 正常返回resolved, 里面有报错则返回rejected
const p1 = Promise.resolve().then(()=>{
return 100
})
console.log(p1) // resolved 触发后续的 then 回调
p1.then(()=>{
console.log('123') // 打印出123
})
const p2 = Promise.resolve().then(()=>{
throw new Error('then Error')
})
console.log(p2) // rejected 触发后续的 catch 回调
p2.then(()=>{
console.log('456') // 触发不了
}).catch(err=>{
console.log('err100',err)
})
- catch 正常返回resolved, 里面有报错则返回rejected
const p3 = Promise.reject('my error').catch(err=>{
console.error(err)
})
console.log(p3) // resolved 注意! 触发 then 回调
p3.then(()=>{
console.log(100)
})
const p4 = Promise.reject('my error').catch(err => {
throw new Error('catch err')
})
console.log(p4) // rejected
p4.then(()=>{
console.log(200) // 不会输出
}).catch(err=>{
console.log('some errors') // some errors
}) // resolved
1.4 相关面试题
// 第一题
Promise.resolve().then(()=>{
console.log(1)
}).catch(()=>{
console.log(2)
}).then(()=>{
console.log(3)
})
// 打印 1 3
// 第二题
Promise.resolve().then(()=>{ // 返回 rejucted状态,rejucted状态,会触发catch
console.log(1)
throw new Error('error1')
}).catch(()=>{ // catch 正常返回resolved,会执行后面的then,但是 里面有报错则返回rejected不会执行后面的then
console.log(2) // 没有报错,执行后面的then
}).then(()=>{
console.log(3)
})
// 打印 1 2 3
// 第三题
Promise.resolve().then(()=>{
console.log(1)
throw new Error('error1')
}).catch(()=>{ // catch 正常返回resolved,会执行后面的then,但是 里面有报错则返回rejected不会执行后面的then
console.log(2) // 没有报错,不会执行后面的catch
}).catch(()=>{
console.log(3)
})
// 打印 1 2
2. async/await:Promise 的语法糖
-
异步回调容易导致callback hell回调地狱。
-
所以有了Promise,Promise的the,catch链式调用虽把层级铺开,但也是基于回调函数。
-
async/await能彻底消灭回调函数,用同步语法编写异步代码。async/await和promise并不冲突。
async function loadData() {
try {
const user = await getUser(userId); // 等待 Promise 完成
const posts = await getPosts(user); // 顺序执行
console.log(posts);
} catch (error) {
console.error("加载失败:", error); // 统一捕获错误
}
}
3. async-await 和 Promise的关系
async-await是消灭异步回调的终极武器,但是和Promise并不互斥,反而,两者相辅相成
-
执行async函数,返回的是
Promise对象
-
await
相当于Promise
的then
-
try...catch
可捕获异常,代替了Promise的catch
async function fn1(){
return 100
}
const res1 = fn1() // 执行async函数,返回的是一个Promise对象
res1.then(data=>{
console.log('data',data) // 100
})
// ****************************
async function fn1(){
return Promise.resolve(200) // 返回的是Promise
}
const res1 = fn1() // 执行async函数,返回的是一个Promise对象
res1.then(data=>{
console.log('data',data) // 200
})
// ****************************
(async function(){
const p1 = Promise.resolve(300)
const data = await p1 // await 相当于 Promise的 then
console.log(data) // 300
})
// ****************************
(async function(){
const data = await 400 // await 相当于 await Promise.resolve(400)
console.log(data) // 400
})()
// ****************************
(async function(){
const p4 = Promise.reject('err1') // rejected 状态
try{
const res = await p4
console.log(res)
}catch(ex){
console.error(ex) // try...catch 可捕获异常,代替了Promise的catch
}
})()
// ****************************
(async function(){
const p4 = Promise.reject('err1') // rejected 状态
const res = await p4
console.log(res) // 不会打印 应为 await 相当于then 但是Promise是rejected 状态,要捕获的话用 try catch
})()
4. 和原理联系在一起
- js是单线程的,异步基于
event loop
async-await
只是一个语法糖,await 之后的代码会被转换为 Promise.then() 回调,放入微任务队列
(Promise属于微任务)
async function async1(){
console.log('async1 start') // 2
await async2()
// 实际等价于
// Promise.resolve(async2()).then(() => {
// console.log('async1 end') // 微任务
// })
// await 后面的代码都可以看作是 callback里的内容,即异步代码
// Promise.resolve().then(()=>{console.log('async1 end')})
console.log('async1 end') // 5
}
async function async2(){
console.log('async2') // 3
}
console.log('script start') // 1
async1()
console.log('script end') // 4
// script start
// async1 start
// async2
// script end
// async1 end
/**
* 解释:
* 同步代码执行阶段:
* console.log('script start') // 1. 同步任务,立即执行
async1() // 2. 调用async1函数(同步调用)
console.log('script end') // 4. 同步任务,立即执行
输出 script start
进入 async1() 执行
执行 async1 函数
console.log('async1 start') // 2. 同步任务,立即执行
await async2() // 3. 调用async2(重点!)
输出 async1 start
执行 await async2():
立即执行 async2() 函数(同步执行)
在 async2() 中输出 async2(同步任务)
async2() 返回的 Promise 会作为 await 的等待对象
await 的转换机制
await async2() 实际等价于:
Promise.resolve(async2()).then(() => {
console.log('async1 end') // 微任务
})
console.log('async1 end') 被放入微任务队列
继续执行同步代码
console.log('script end') // 4. 同步任务
*/
// ****************************
async function async1(){
console.log('async1 start') // 2
await async2()
// 实际等价于
// Promise.resolve(async2()).then(() => {
// console.log('async1 end') // 5
// Promise.resolve(async3()).then(() => {
// console.log('async1 end 2') // 7
// })
// })
// await 后面的代码都可以看作是 callback里的内容,即异步代码
// Promise.resolve().then(()=>{console.log('async1 end')})
console.log('async1 end') // 5
await async3()
// 下面一行是异步回调的内容
console.log('async1 end 2') // 7
}
async function async2(){
console.log('async2') // 3
}
async function async3(){
console.log('async3') // 6
}
console.log('script start') // 1
async1()
console.log('script end') // 4
// script start
// async1 start
// async2
// script end
// async1 end
// async3
// async1 end 2
5. 有关异步的面试练习题
- 输出顺序
async function async1(){
console.log('async1 start') // 2
await async2()
// await 后面的都作为回调内容 --微任务(排队 进入micro task queue)
console.log('async1 end') // 6
}
async function async2(){
console.log('async2') // 3
}
console.log('script start') // 1
setTimeout(function(){ // 宏任务
console.log('setTimeout') // 8
},0)
async1()
new Promise(function (resolve){ // 初始化 promise时,传入的函数会立刻被执行
console.log('promise1') // 4
resolve()
}).then(function (){ // 微任务(排队 进入micro task queue)
console.log('promise2') // 7
})
console.log('script end') // 5
- 输出结果
setTimeout(()=>{
console.log('1')
},0)
new Promise((resolve,reject)=>{
console.log('2')
resolve('p1')
new Promise((resolve,reject)=>{
console.log('3')
setTimeout(()=>{
resolve('setTimeout2')
console.log('4')
},0)
resolve('p2')
}).then(data=>{
console.log(data)
})
setTimeout(()=>{
resolve('setTimeout1')
console.log('5')
},0)
}).then(data=>{
console.log(data)
})
console.log('6')
// 2,3,6,p2,p1,1,4,5
- 输出结果
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('setTimeout')
},0)
async1()
// script start,async1 start,async2,async1 end,setTimeout
点击 JS基础-三座大山之三一异步(1)进行学习异步基础