🧠前端面试高频考题---promise,从五个方面搞定它🛠️

前言

在面试之中关于promise经常被问起!这也许是因为我们的js充满了异步函数,而promise是用来处理异步操作的重要方案,所以今天让我们来全面的学习一下🚀🚀🚀

介绍

Promise 是 JavaScript 异步编程的重要知识点,既是面试常客,也是高频考点。接下来让我们从 核心概念API 详解手写实现经典面试题实践例题 五个角度拿下promise

1.核心概念

1.promise是什么?

简单来说就是一种异步编程的模式,用于处理异步操作且可以避免出现回调地狱的问题,它表示一个异步操作,这个操作可能完成也可能失败,并将结果,错误通过状态机制传递。

2.promise的三种状态

  • pending(待定) :初始状态,异步操作尚未完成。
  • fulfilled(已完成) :异步操作成功,调用 .then()
  • rejected(已拒绝) :异步操作失败,调用 .catch()

⚠️ Promise 状态一旦从 pending 转变为 fulfilledrejected,就不可逆

你可以将 Promise 视为一个容器,用于封装未来的值(异步操作的结果)。通过 .then() 方法可以处理 fulfilled 的结果,通过 .catch() 方法可以捕获 rejected 的错误。

Promise API详解

1. Promise.prototype.then()

  • 接收两个回调函数(onFulfilledonRejected),分别处理成功和失败,onFulfilled的值就是Promise 被 resolved 时返回的对象,同样的onRejected
  • .then() 返回一个新的 Promise,因此可链式调用。

⚠️ .then() 中若没有返回值,默认返回 undefined

js 复制代码
function fetchData() {
  return new Promise((resolve, reject) => {
    // 模拟网络请求,1 秒后返回结果
    setTimeout(() => {
      const success = true; // 假设请求成功
      if (success) {
        resolve("Data fetched successfully");
      } else {
        reject("Failed to fetch data");
      }
    }, 1000);
  });
}

fetchData()
  .then(
    (result) => {
      console.log("Success:", result); // 处理成功的回调
      return "Processed data"; // 返回一个新的promise对象
    },
    (error) => {
      console.error("Error:", error); // 处理失败的回调
    }
  )
  .then((processedResult) => {
    console.log("Processed Result:", processedResult); // 处理上一个 then 返回的结果
  })
  .catch((err) => {
    console.error("Caught Error:", err); // 捕获整个链中的错误
  });

在上面的例子中我们给.then传了两个回调函数,一个处理成功 一个处理失败,但一般情况下我们更喜欢使用.catch()来处理promise的失败情况。

⚠️ 还有一个值得注意的是.then() 中无论你返回什么,都会被包装成一个 Promise 对象,就比如你返回一个普通值也会被包装成Promise.resolve(),这保证了promise的链式调用。

2. Promise.prototype.catch()

  • 专门捕获 Promise 中的异常或 .then() 的失败回调。

这没什么好讲的,我们可以在链式中使用.catch()来捕获失败或异常同样的.catch()的返回始终是一个promise对象,默认为underfined。

3. Promise.prototype.finally()

  • 无论 Promise 成功或失败,finally() 都会执行。
  • 通常用于资源释放加载动画关闭等场景。

4. Promise.all()

  • 接收一个 Promise 数组,全部成功 时才会进入 .then();任意一个失败,立即进入 .catch()
  • 适用于所有任务必须成功的场景。
js 复制代码
Promise.all([
  Promise.resolve("任务1完成"),
  Promise.resolve("任务2完成"),
  Promise.reject("任务3失败")
])
  .then(console.log)  // 不会执行
  .catch(console.error);  // 输出:"任务3失败"

promise.all()在实际的应用场景很多,比如在处理并发异步任务的时候,我们在项目中经常需要同时请求多个接口的数据,例如在查看你的掘金个人主页的时候需要同时获取你的信息,你的文章数据等。

javascript 复制代码
function getUserInfo() {
  return fetch("https://jsonplaceholder.typicode.com/users/1").then(res => res.json());
}

function getPosts() {
  return fetch("https://jsonplaceholder.typicode.com/posts").then(res => res.json());
}

function getComments() {
  return fetch("https://jsonplaceholder.typicode.com/comments").then(res => res.json());
}

Promise.all([getUserInfo(), getPosts(), getComments()])
  .then(([user, posts, comments]) => {
    console.log("用户信息:", user);
    console.log("文章数据:", posts);
    console.log("评论数据:", comments);
  })
  .catch(error => {
    console.error("某个请求失败:", error);
  });

其还常用于加载多个静态资源

js 复制代码
function loadImage(src) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = src;
    img.onload = () => resolve(`${src} 加载成功`);
    img.onerror = () => reject(`${src} 加载失败`);
  });
}

Promise.all([
  loadImage('image1.jpg'),
  loadImage('image2.jpg'),
  loadImage('image3.jpg')
])
.then(results => console.log("全部图片加载成功:", results))
.catch(error => console.error("某张图片加载失败:", error));

例如并行加载多张图片,其可以提高页面的性能,promise.all()确保所有的图片加载完成了以后才会.then()操作非常适合轮播图,和懒加载等场景!

5. Promise.race()

  • 接收一个 Promise 数组,第一个完成Promise(无论成功或失败)就决定最终结果。
  • 常用于请求超时控制
js 复制代码
Promise.race([
  new Promise(resolve => setTimeout(() => resolve("请求成功"), 1000)), // 请求成功的时间改为1秒
  new Promise((_, reject) => setTimeout(() => reject("请求超时"), 2000)) // 超时时间保持为2秒
])
.then(console.log)  // 输出:"请求成功"
  .catch(console.error);

这里我们设置的在一秒时间内完成了请求就会输出请求成功,但要是由于网络延迟、服务器响应慢等原因未能在1秒内完成,且两秒后还没完成就会输出请求超时。

6. Promise.allSettled()

  • 接收一个 Promise 数组,无论成功或失败都会将所有结果返回。

  • 每个结果对象包含:

    • { status: "fulfilled", value: 数据 }
    • { status: "rejected", reason: 错误信息 }

就例如我们在批量删除时,即使有几项删除失败,其他仍可以删除成功。相同的其还经常应用在备份数据,用户并行操作等。

Promise 经典面试题

1.与event loop结合考察执行顺序

Promise.then() 属于微任务 ,在当前同步代码执行完毕后执行。 具体的关于event loop的介绍可以看我这篇文章:envent Loop

2. Promise 链式调用中的返回值

js 复制代码
Promise.resolve(1)
  .then(x => x + 1)
  .then(x => { throw new Error("出错了"); })
  .catch(err => console.error(err.message))
  .then(x => console.log("继续执行", x));
javascript 复制代码
答案:
出错了
继续执行 undefined
执行过程分析:
首先1会传到第一个.then()中然后返回一个2进入第二个.then()中,其抛出了一个错误,被catch捕获并输出:出错了,因其没有设置返回值默认返回underfined,underfined传入下一个then输出:继续执行 underfined

3. 手写 Promise 实现(高频)

首先我们先整理一下思路:

  1. 状态(State) :一个 Promise 对象有三种可能的状态:

    • pending(等待中)
    • fulfilled(已完成/成功)
    • rejected(已拒绝/失败)
  2. 函数参数resolvereject

    • resolve:异步操作成功后调用,将promise的状态变为fulfilled并将异步操作的结果传递给 .then() 方法中的成功回调。
    • reject:异步操作失败后调用,将promise的状态变为rejected将异步操作失败的原因传递给.catch()方法。 3.链式调用.then()要返回一个新的promise对象以支持链式调用。
kotlin 复制代码
手写代码

class MyPromise {
  constructor(executor) {
    this.status = "pending";  // 初始状态
    this.value = undefined;   // 成功的值
    this.reason = undefined;  // 失败的原因

    // 用于存储回调函数,确保异步情况也能调用
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === "pending") {
        this.status = "fulfilled";
        this.value = value;

        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    const reject = (reason) => {
      if (this.status === "pending") {
        this.status = "rejected";
        this.reason = reason;

        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    try {
      executor(resolve, reject); // 立即执行传入的执行器函数
    } catch (error) {
      reject(error); // 捕获同步错误
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      if (this.status === "fulfilled") {
        try {
          const result = onFulfilled(this.value);
          resolve(result); // 将结果传递给下一个 then
        } catch (error) {
          reject(error);
        }
      }

      if (this.status === "rejected") {
        try {
          const result = onRejected(this.reason);
          resolve(result); // 继续执行下一个 then(如果有返回值)
        } catch (error) {
          reject(error);
        }
      }

      if (this.status === "pending") {
        // 异步情况,存储回调
        this.onFulfilledCallbacks.push(() => {
          try {
            const result = onFulfilled(this.value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });

        this.onRejectedCallbacks.push(() => {
          try {
            const result = onRejected(this.reason);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(callback) {
    return this.then(
      value => {
        callback();
        return value;
      },
      reason => {
        callback();
        throw reason;
      }
    );
  }
}

经典面试题

  • Promise 的状态一旦变更,是否可以再改变?

  • 如何使用 Promise.race() 实现请求超时控制?

  • Promise 和 async/await 有什么异同?

🎯 总结

Promise 的三种状态及其不可逆性

Promise 链式调用原理

.then().catch().finally() 的执行顺序

Promise.all() vs Promise.race() vs Promise.any()

Promiseasync/await 的区别

PromisesetTimeout(微任务 vs 宏任务)

✅ 手写 Promise 实现

相关推荐
Jiude19 分钟前
UnoCSS presetWind4() 背景色使用 color-mix() 的原因及解决方案
前端·css
无名之逆1 小时前
Hyperlane:Rust 生态中的轻量级高性能 HTTP 服务器库,助力现代 Web 开发
服务器·开发语言·前端·后端·http·面试·rust
范哥来了1 小时前
python web开发django库安装与使用
前端·python·django
烛阴1 小时前
JavaScript 的 “new Function”:你不知道的黑魔法,让代码更灵活!
前端·javascript
ConardLi1 小时前
发布第五天,我的开源项目突破 1.7 K Star!
前端·javascript·人工智能
Moment2 小时前
京东一面:postMessage 如何区分不同类型的消息 🤪🤪🤪
前端·javascript·面试
鱼樱前端2 小时前
🔥 Vue2 vs Vue3 的 h 函数终极指南:从入门到源码级深度解析
前端·vue.js
独行soc2 小时前
2025年渗透测试面试题总结-某四字大厂面试复盘 一面(题目+回答)
网络·python·科技·面试·职场和发展·红蓝攻防
Moment2 小时前
💯 铜三铁四,我收集整理了这些大厂面试场景题 (一)
前端·后端·面试
小杨xyyyyyyy2 小时前
Mysql - 日志相关问题
数据库·mysql·面试