jQuery deferred.isRejected() 方法(长文讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

从异步编程谈起:为什么需要 Deferred?

在现代 Web 开发中,异步编程几乎无处不在。无论是 AJAX 请求、DOM 操作还是定时器,开发者都需要处理非阻塞操作。但传统的回调函数模式存在“回调地狱”(Callback Hell)问题,代码可读性差且难以维护。为了解决这一痛点,jQuery 引入了 Deferred 对象,它提供了一种更结构化的方式来管理异步任务。

Deferred 对象的核心思想是将异步操作封装成一个对象,通过链式调用和状态管理来简化代码逻辑。其状态机设计借鉴了 Promise/A+ 规范,支持 pending(未决)、resolved(已解决)和 rejected(已拒绝)三种状态。而 isRejected() 方法正是用于检测 Deferred 对象是否处于拒绝状态的关键工具。


Deferred 对象的核心概念

Promise 与 Deferred 的关系

在理解 isRejected() 之前,需要明确两个概念:

  1. Promise 对象:表示异步操作的最终结果,提供 then()catch() 等方法
  2. Deferred 对象:Promise 的工厂,提供 resolve()reject()promise() 等控制方法

可以将 Deferred 比作快递公司的物流系统:

  • Promise 是客户看到的物流状态(是否已签收)
  • Deferred 是快递员操作的内部系统(决定包裹是否送达或退回)
const deferred = $.Deferred();
const promise = deferred.promise();

三态模型详解

Deferred 对象的状态变化遵循严格的规则:

状态触发条件典型应用场景
pending初始状态请求尚未完成
resolved调用 deferred.resolve()数据成功加载
rejected调用 deferred.reject()网络错误或验证失败

当状态变为 rejected 时,所有通过 promise.catch() 注册的回调将被触发。


isRejected() 方法深度解析

方法定义与返回值

deferred.isRejected() 是一个判断 Deferred 对象状态的检测方法,返回布尔值:

  • 返回 true:当且仅当 Deferred 处于 rejected 状态
  • 返回 false:对象处于 pendingresolved 状态

isResolved() 形成互补关系,两者不可能同时为真。

使用场景与常见误区

典型用例:显式状态检查

在某些需要手动干预逻辑分支的场景中,直接检查状态比依赖回调更直观:

const dfd = $.Deferred();

setTimeout(() => {
  dfd.reject("网络超时");
}, 1000);

// 主线程中检查状态
const checkStatus = () => {
  if (dfd.isRejected()) {
    console.log("任务失败:", dfd.reason());
  } else {
    console.log("仍在处理中");
  }
};

// 每 500ms 检查一次
setInterval(checkStatus, 500);

需避免的错误模式

  1. 状态检查的时效性
    因为 JavaScript 是单线程的,isRejected() 只能检测调用时的瞬时状态。若在异步操作未完成前调用,可能得到 false 的误判。

  2. catch() 的冲突
    如果同时使用 catch()isRejected(),需注意回调函数的执行顺序。例如:

dfd.promise()
  .then(() => console.log("成功"))
  .catch(() => console.log("失败"));
  
if (dfd.isRejected()) { // 可能未触发
  // 可能未执行到此判断
}

实战案例:结合 AJAX 请求

案例背景

假设需要从服务器获取用户数据,但存在可能的网络错误或身份验证失败的情况。我们希望:

  1. 显式检测请求是否失败
  2. 根据失败原因显示不同提示信息
function fetchData() {
  const dfd = $.Deferred();
  
  $.ajax({
    url: "/api/user",
    success: (data) => dfd.resolve(data),
    error: (xhr) => {
      if (xhr.status === 401) {
        dfd.reject("未授权访问");
      } else {
        dfd.reject("网络错误");
      }
    }
  });
  
  return dfd.promise();
}

// 调用方代码
const deferred = fetchData();
deferred.then(
  (data) => console.log("数据:", data),
  (reason) => console.error("错误:", reason)
);

// 1秒后检查状态(模拟延迟操作)
setTimeout(() => {
  if (deferred.isRejected()) {
    const message = deferred.reason() === "未授权访问" 
      ? "请重新登录" 
      : "连接服务器失败";
    alert(message);
  }
}, 1000);

关键点解析

  1. Deferred 与原生 AJAX 的结合
    通过手动创建 Deferred 对象,将传统回调模式转换为 Promise 风格,增强代码的可维护性。

  2. reason() 方法的作用
    该方法返回 reject() 时传入的参数,可用于获取具体的错误信息。


进阶技巧:与 then() 的协同使用

状态检测与回调链的结合

const dfd = $.Deferred();

setTimeout(() => dfd.reject("任务终止"), 1000);

dfd.then(
  (result) => console.log("成功:", result),
  (error) => console.error("失败:", error)
).then(() => {
  // 第二个 then 的执行取决于前一个 promise 的状态
  if (dfd.isRejected()) {
    console.log("最终状态确认为已拒绝");
  }
});

自定义错误处理逻辑

通过结合 isRejected() 可实现更灵活的错误重试策略:

function retryOnFailure(deferred, maxRetries) {
  return new Promise((resolve, reject) => {
    const check = () => {
      if (deferred.isRejected() && maxRetries > 0) {
        console.log(`重试剩余次数: ${maxRetries}`);
        maxRetries--;
        // 模拟重新执行操作
        someOperation().then(resolve, check);
      } else {
        deferred.then(resolve, reject);
      }
    };
    check();
  });
}

总结与最佳实践

核心知识点回顾

  1. 状态检测的时机选择:优先使用 then/catch 处理异步结果,仅在必要时使用 isRejected()
  2. 错误信息的封装:通过 reject() 传递有意义的错误对象或字符串
  3. 与原生 Promise 的兼容性:jQuery Deferred 兼容 ES6 Promise,但需注意 API 差异

开发建议

  • 在复杂异步流程中,结合 isRejected() 与状态机模式(如 FSM)管理任务状态
  • 避免在 UI 渲染线程中频繁调用状态检测方法,可采用事件监听模式
  • 对于现代项目,建议逐步迁移到原生 fetch()async/await,但理解 Deferred 仍对兼容旧系统有帮助

通过掌握 jQuery deferred.isRejected() 方法,开发者能更精准地控制异步流程,减少因状态判断失误导致的逻辑漏洞。在异步编程这条“马拉松”中,每个状态检测点都是确保程序健壮性的“路标”,而 Deferred 对象正是帮助开发者看清这些路标的导航仪。

最新发布