作为前端开发者,数据请求是核心技能之一,需要掌握的知识可以分为几个层次:

一、数据请求需要掌握的核心内容

  1. 基础请求方式

    • 了解 XMLHttpRequest 的工作原理(虽然实际开发中很少直接用,但能帮助理解底层)。
    • 熟练使用 Fetch API(浏览器原生,基于 Promise),掌握其配置项(method、headers、body、credentials 等)。
    • 熟悉主流请求库(如 Axios)的使用,包括拦截器、请求 / 响应配置、取消请求等高级功能。
  2. 异步处理机制

    • 深刻理解 Promise 的原理和使用(链式调用、错误捕获)。
    • 熟练使用 async/await 语法简化异步代码。
    • 处理并发请求(如 Promise.allPromise.race 等)。
  3. 错误与异常处理

    • 网络错误(断网、超时)的捕获与处理。
    • HTTP 错误状态码(4xx、5xx)的统一处理。
    • 接口返回的业务错误(如权限不足、数据格式错误)的处理逻辑。
  4. 跨域问题

    • 理解跨域的原因(浏览器同源策略)。
    • 掌握常见跨域解决方案(CORS、JSONP、代理服务器等)。
  5. 请求优化

    • 缓存策略(强缓存、协商缓存)。
    • 请求合并、防抖节流(避免频繁请求)。
    • 大文件分片上传、断点续传等场景处理。

二、手写 Promise(符合 Promise/A+ 规范核心特性)

Promise 是异步编程的解决方案,核心是状态管理(pending → fulfilled/rejected,状态不可逆)和链式调用。以下是一个简化实现:

class MyPromise {
  // 构造函数接收执行器(executor)
  constructor(executor) {
    // 初始状态为pending
    this.status = 'pending';
    // 成功的值
    this.value = undefined;
    // 失败的原因
    this.reason = undefined;
    // 成功回调队列(处理异步情况)
    this.onFulfilledCallbacks = [];
    // 失败回调队列
    this.onRejectedCallbacks = [];

    // 成功回调(状态变为fulfilled)
    const resolve = (value) => {
      // 状态只能从pending改变
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.value = value;
        // 执行所有缓存的成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // 失败回调(状态变为rejected)
    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方法:接收成功和失败回调,返回新Promise实现链式调用
  then(onFulfilled, onRejected) {
    // 处理回调非函数的情况(值穿透)
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' 
      ? onRejected 
      : reason => { throw reason; };

    // 返回新Promise,实现链式调用
    const newPromise = new MyPromise((resolve, reject) => {
      // 状态为fulfilled时执行
      if (this.status === 'fulfilled') {
        // 用setTimeout模拟异步(Promise回调需异步执行)
        setTimeout(() => {
          try {
            // 执行成功回调,获取返回值
            const result = onFulfilled(this.value);
            // 解析返回值(如果是Promise则等待其完成,否则直接resolve)
            this.resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      // 状态为rejected时执行
      if (this.status === 'rejected') {
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            this.resolvePromise(newPromise, result, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      // 状态为pending时,缓存回调
      if (this.status === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onFulfilled(this.value);
              this.resolvePromise(newPromise, result, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

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

    return newPromise;
  }

  // 解析then回调的返回值(处理返回Promise的情况)
  resolvePromise(newPromise, result, resolve, reject) {
    // 避免循环引用(如then返回自身)
    if (newPromise === result) {
      return reject(new TypeError('Chaining cycle detected for promise'));
    }

    // 如果返回值是Promise,等待其完成
    if (result instanceof MyPromise) {
      result.then(resolve, reject);
    } else {
      // 非Promise直接resolve
      resolve(result);
    }
  }

  // 静态方法:快速创建成功的Promise
  static resolve(value) {
    return new MyPromise(resolve => resolve(value));
  }

  // 静态方法:快速创建失败的Promise
  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason));
  }
}

核心特性说明

  1. 状态管理:通过 pendingfulfilled/rejected 的不可逆状态,保证回调只执行一次。
  2. 异步处理:用 setTimeout 模拟微任务(实际 Promise 用微任务队列),确保回调异步执行。
  3. 链式调用then 方法返回新的 Promise,通过 resolvePromise 处理回调返回值(支持返回 Promise 或普通值)。
  4. 值穿透:当 then 的参数不是函数时,会忽略该回调,直接将值传递给下一个 then

掌握这些内容后,就能应对前端大部分数据请求场景,以及理解异步编程的核心逻辑了。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐