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种状态

  1. Pending(等待中):初始状态,既未完成也未拒绝

  2. Fulfilled(已兑现):异步操作成功完成,调用 resolve() 后进入此状态

  3. 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改变状态

  1. 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)
})

  1. 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并不互斥,反而,两者相辅相成

  1. 执行async函数,返回的是Promise对象

  2. await 相当于 Promisethen

  3. 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. 有关异步的面试练习题

  1. 输出顺序
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
  1. 输出结果
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

任务队列执行的顺序练习1

  1. 输出结果
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

任务队列执行的顺序练习2

点击 JS基础-三座大山之三一异步(1)进行学习异步基础

posted @ 2025-08-18 16:10  cyy618  阅读(6)  评论(0)    收藏  举报