Promise详解及面试例题

1、Promise的基本概念

1.1、基本概念:

  1. PromiseJavaScript中的一种用于处理异步操作的对象
  2. 可以把它想象成一个“承诺”——程序承诺会在未来的某个时间点完成某件事(比如从服务器获取数据),但是,并不立即返回结果。

1.2、Promise的状态:

Promise 有三种状态:

  1. Pending(进行中): 承诺还没有完成,也没有失败,它正在等待某件事情发生。
  2. Fulfilled(已完成): 承诺成功地完成了,并且返回了一个结果。
  3. Rejected(已失败) : 承诺未能完成,发生了某种错误或问题。

1.3、生活场景示例:

假设小明让小红帮忙买咖啡,小红答应了,这时,这个“答应”的过程就是一个Promise,它可能有三种状态:

  • Pending:小红还在咖啡店排队,咖啡还没买到手。
  • Fulfilled:小红已经买到咖啡,并且把咖啡给了小明。
  • Rejected:小红因为某种原因没法买到咖啡,告诉小明:“抱歉,没买到”。

2、Promise的链式调用规则

Promise的链式调用是指:

  1. 在一个Promise.then() 方法中返回一个新的Promise,然后可以继续在这个新的Promise上调用.then() 方法
  2. 这种方式可以:让我们可以把多个异步操作串联起来,依次处理,避免回调地狱。
  1. .then()返回的是一个新的Promise
    • 每次调用.then() 方法后,你都会得到一个新的Promise
    • 这使得你可以在下一个.then()里继续处理上一个.then()的结果。
  2. .then() 的回调函数可以返回值:
    • 如果回调函数返回的是一个普通的值(而不是 Promise),这个值会被包装成一个已经完成的 Promise,并传递给下一个 .then()
  3. 回调函数返回的是Promise
    • 如果回调函数返回的是一个Promise,那么下一个.then()将会等待这个Promise完成,然后继续处理结果。
  4. 错误传递:
    • 如果任何一个.then()中发生错误(包括抛出异常或返回一个被拒绝的 Promise),这个错误会被传递到后面最近的.catch()中处理。

3、Promise的静态方法

  1. Promise.resolve(value):
    • 用来快速创建一个已经完成的Promise,并将给定的value作为结果。
    • 适用于:将一个普通的值或非Promise的结果转换为Promise
  2. Promise.reject(reason):
    • 用来快速创建一个被拒绝的Promise,并将给定的 reason 作为错误原因。
    • 适用于:将一个错误或失败的结果转换为 Promise
  3. Promise.all(iterable):
    • 接受一个可迭代对象(通常是一个数组)作为参数,其中每个元素都是一个 Promise。
    • 只有当所有的 Promise 都完成时,返回的 Promise 才会被完成,结果是一个包含所有结果的数组
    • 如果有任何一个Promise被拒绝,Promise.all会立即返回一个被拒绝的Promise
  4. Promise.race(iterable):
    • 接受一个可迭代对象,其中每个元素也是一个 Promise。
    • 返回的 Promise 会在第一个 Promise 完成或拒绝时,采用这个 Promise 的结果或错误。
    • 适用于:你只关心最先完成的异步操作的场景
  5. Promise.allSettled(iterable):
    • 接受一个可迭代对象,每个元素是一个 Promise。
    • 返回的 Promise 会等待所有的 Promise 都结束(无论是完成还是拒绝),并返回一个数组,数组中的每一项都是一个对象,表示每个 Promise 的状态和结果。
    • 适用于:你希望等待所有 Promise 结束后,处理每个 Promise 的结果
  6. Promise.any(iterable):
    • 接受一个可迭代对象,每个元素是一个 Promise。
    • 返回的 Promise 会在第一个成功(fulfilled)的 Promise 完成时被完成。如果所有的 Promise 都被拒绝,返回的 Promise 会被拒绝,错误信息是所有错误的一个数组。
    • 适用于:你只关心最先成功的异步操作的场景

4、async和await

  • asyncawaitJavaScript中用于处理异步操作的关键字
  • 它们让你能够像写同步代码那样编写异步代码,使得代码更加清晰和易读。

4.1、async 函数

  • async是用来定义一个异步函数关键字
  • 一个函数一旦被定义为 async,它就会自动返回一个 Promise,而不论你在函数中实际返回的是什么。

4.2、await 关键字

  • await只能在async函数内部使用。
  • 它用于等待一个Promise完成,并获得Promise解决的值
  • 简单理解:
    • 使用await,就像在告诉JS:“等一下,等这个Promise完成了,再继续执行后面的代码。”

4.3、async 和 await 的好处:

  • 更易读:它让你可以像写同步代码一样写异步代码,不需要再用.then()链式调用,代码逻辑更直观
  • 错误处理:你可以使用try...catch语句来处理异步操作中的错误,这样比处理Promise.catch()更加清晰。

5、事件循环中,Promise进入的是哪些事件队列

以下:包含一些常规的事件队列总结

  1. setTimeout的回调:宏任务(macro task)
  2. setInterval的回调:宏任务(macro task)
  3. promisethen函数回调:微任务(micro task)
  4. requestAnimationFrame的回调:介于宏任务和微任务之间,但通常被归类为宏任务(macro task)
  5. 事件处理函数:宏任务(macro task)

6、面试例题

根据下列代码,判断代码输出的结果是什么:

// 下面代码的输出结果是什么 => 先后打印:1、2、4、3
    const promise = new Promise((resolve, reject) => {
      console.log(1);
      resolve();
      console.log(2);
    });

    promise.then(() => {
// 这里不先打印`3`是因为:promise里的then回调会进入"微任务队列",它必须等待全局(同步)代码执行完成后,再执行微队列里的代码
      console.log(3); 
    });

    console.log(4);
// 下面代码的输出结果是什么 => 1、5、2、3、4
      const promise =new Promise((resolve,reject)=>{
  // 1)同步代码先执行 => 打印1
        console.log(1);
  // 2)延时器进入宏队列,等待处理
  // 5)处理宏队列任务
        setTimeout(()=>{
    // 5-1、打印输出2
          console.log(2);
    // 5-2、将Promise对象状态改为成功状态 => 回调函数进入微队列,但,需要等到当前宏队列任务完成后才能执行微队列任务
          resolve();
    // 5-3、打印输出3
          console.log(3);
        }); 
      });
  // 3)因为promise对象此时还是pending状态,没有满足成功状态,此时这里代码也是不执行的,也不会放入微队列
      promise.then(()=>{
  // 6)处理微队列任务 => 打印输出4
        console.log(4);
      });
  // 4)执行同步代码 => 打印5
      console.log(5);
// 下面代码的输出结果是什么
     const promise1 = new Promise((resolve, reject)=>{
       setTimeout(()=>{
         resolve()
       },1000)
     })
     const promise2 = promisel.catch(()=>{
       return 2;
     })
// 因为:它们还在等待`resolve`或`reject`状态
  // 1)打印:promise1 Promise{<pending>} 
  // 2)打印:promise2 Promise{<pending>}
     console.log('promise1', promise1)
     console.log('promise2', promise2)
     
     setTimeout(()=>{
// 因为:`promise1`被`resolve`后,状态变为`fulfilled`,且`resolve()`没有传递值,所以`fulfilled`的值是`undefined`。
  // 3)打印:promise1 Promise{<undefined>}
  // 4)打印:promise2 Promise{<undefined>}
       console.log('promise1', promise1)
       console.log('promise2',promise2)
     },2000)
// 下面代码的输出结果是什么 => 0、2、1
    async function m(){
  // 1)立即执行,打印 0
      console.log(0)
  // 2)遇到await,m函数则暂停执行,将返回的1包装成一个已解决的Promise,这时控制权返回到主线程,继续执行同步代码
      const n = await 1;
  // 4)等待获取l的结果后再执行
      console.log(n);
    }
    m();
  // 3)同步代码立即执行,打印2
    console.log(2);
// 下面代码的输出结果是什么 => 0、3、1、2
     async function m(){
  // 1)立即执行,打印0
       console.log(0)
  // 2)await表达式会立即执行(即 Promise.resolve(1)),但,会让出执行线程
       const n = await 1;
  // 5)在微任务队列中执行,await完成后打印 1
       console.log(n);
     }
     
     (async ()=>{
  // 4) 调用 m(),进入 m 函数,暂停在 await 处
       await m();
  // 6) 在 m() 执行完后,打印 2
       console.log(2);
     })();
  // 3) 同步代码立即执行,打印 3   
     console.log(3);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值