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()
之前,需要明确两个概念:
- Promise 对象:表示异步操作的最终结果,提供
then()
、catch()
等方法 - 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
:对象处于pending
或resolved
状态
与 isResolved()
形成互补关系,两者不可能同时为真。
使用场景与常见误区
典型用例:显式状态检查
在某些需要手动干预逻辑分支的场景中,直接检查状态比依赖回调更直观:
const dfd = $.Deferred();
setTimeout(() => {
dfd.reject("网络超时");
}, 1000);
// 主线程中检查状态
const checkStatus = () => {
if (dfd.isRejected()) {
console.log("任务失败:", dfd.reason());
} else {
console.log("仍在处理中");
}
};
// 每 500ms 检查一次
setInterval(checkStatus, 500);
需避免的错误模式
-
状态检查的时效性
因为 JavaScript 是单线程的,isRejected()
只能检测调用时的瞬时状态。若在异步操作未完成前调用,可能得到false
的误判。 -
与
catch()
的冲突
如果同时使用catch()
和isRejected()
,需注意回调函数的执行顺序。例如:
dfd.promise()
.then(() => console.log("成功"))
.catch(() => console.log("失败"));
if (dfd.isRejected()) { // 可能未触发
// 可能未执行到此判断
}
实战案例:结合 AJAX 请求
案例背景
假设需要从服务器获取用户数据,但存在可能的网络错误或身份验证失败的情况。我们希望:
- 显式检测请求是否失败
- 根据失败原因显示不同提示信息
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);
关键点解析
-
Deferred 与原生 AJAX 的结合
通过手动创建 Deferred 对象,将传统回调模式转换为 Promise 风格,增强代码的可维护性。 -
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();
});
}
总结与最佳实践
核心知识点回顾
- 状态检测的时机选择:优先使用
then/catch
处理异步结果,仅在必要时使用isRejected()
- 错误信息的封装:通过
reject()
传递有意义的错误对象或字符串 - 与原生 Promise 的兼容性:jQuery Deferred 兼容 ES6 Promise,但需注意 API 差异
开发建议
- 在复杂异步流程中,结合
isRejected()
与状态机模式(如 FSM)管理任务状态 - 避免在 UI 渲染线程中频繁调用状态检测方法,可采用事件监听模式
- 对于现代项目,建议逐步迁移到原生
fetch()
或async/await
,但理解 Deferred 仍对兼容旧系统有帮助
通过掌握 jQuery deferred.isRejected() 方法
,开发者能更精准地控制异步流程,减少因状态判断失误导致的逻辑漏洞。在异步编程这条“马拉松”中,每个状态检测点都是确保程序健壮性的“路标”,而 Deferred 对象正是帮助开发者看清这些路标的导航仪。