jQuery deferred.promise() 方法(长文讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 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+ 小伙伴加入学习 ,欢迎点击围观
前言:为什么需要异步编程?
在现代 Web 开发中,异步编程是绕不开的话题。无论是加载数据、处理用户输入,还是执行复杂的计算,开发者都需要与异步操作打交道。然而,异步编程容易引发“回调地狱”(Callback Hell),导致代码结构混乱、难以维护。
为了解决这一问题,jQuery 引入了 Deferred 对象 和 Promise 对象,并通过 deferred.promise()
方法实现了对异步任务的优雅管理。本文将从基础概念讲起,逐步解析 deferred.promise()
的核心作用,并通过案例演示其在实际开发中的应用。
一、Deferred 对象:异步任务的“控制中心”
1.1 Deferred 是什么?
Deferred 对象是 jQuery 提供的一个核心工具,用于管理异步任务的生命周期。它可以被看作一个“任务协调者”,负责记录异步操作的状态(如成功、失败、完成),并允许开发者在状态变化时执行相应的回调函数。
形象比喻:
假设你是一家快递公司的老板,Deferred 就像你的中央调度系统。当你收到订单(创建 Deferred 对象)后,系统会跟踪包裹的运输状态(如“已发货”“运输中”“已签收”),并通知客户(通过回调函数)状态更新。
1.2 Deferred 的核心方法
deferred.resolve()
:标记任务成功完成。deferred.reject()
:标记任务失败。deferred.notify()
:在任务执行过程中发送进度通知。
示例代码:
const deferred = jQuery.Deferred();
// 模拟异步任务
setTimeout(() => {
if (/* 任务成功 */ true) {
deferred.resolve("任务完成");
} else {
deferred.reject("任务失败");
}
}, 1000);
deferred.done((result) => {
console.log("成功回调:", result); // "任务完成"
});
deferred.fail((error) => {
console.log("失败回调:", error);
});
二、Promise 对象:外部观察的“窗口”
2.1 Promise 的作用
Promise 对象是 Deferred 的“观察者”,它允许外部代码(如其他模块或函数)订阅 Deferred 的状态变化,但无法直接修改任务的执行流程。
关键区别:
| 特性 | Deferred | Promise |
|------------------|------------------------------|---------------------------|
| 可操作性 | 可调用 resolve()
等方法 | 仅能监听状态变化 |
| 设计目的 | 控制任务流程 | 观察任务状态 |
| 适用场景 | 任务发起者内部使用 | 外部代码订阅任务结果 |
2.2 为什么需要 deferred.promise()?
通过 deferred.promise()
方法,可以将 Deferred 对象转换为 Promise 对象,从而:
- 封装内部逻辑:外部代码无法直接操作 Deferred,避免意外修改任务状态。
- 解耦代码:调用者只需关注任务结果,无需了解任务的具体实现。
示例代码:
const deferred = jQuery.Deferred();
const promise = deferred.promise();
// 外部代码只能监听,无法修改任务状态
promise.then((result) => {
console.log("外部监听到成功:", result);
});
// 内部仍可控制任务流程
setTimeout(() => deferred.resolve("内部完成"), 1000);
三、deferred.promise() 的核心用法
3.1 基础用法:将 Deferred 转换为 Promise
const deferred = jQuery.Deferred();
const promise = deferred.promise();
promise
.then((result) => console.log("成功:", result))
.catch((error) => console.error("失败:", error));
3.2 与 AJAX 结合:优雅处理异步请求
在 AJAX 请求中,jQuery 默认返回一个 Promise 对象。但若需自定义逻辑(如多次调用),可手动创建 Deferred:
function fetchData() {
const deferred = jQuery.Deferred();
jQuery.ajax({
url: "/api/data",
success: (data) => deferred.resolve(data),
error: (xhr) => deferred.reject(xhr),
});
return deferred.promise(); // 返回 Promise 对象
}
fetchData()
.then((data) => console.log("数据加载成功:", data))
.catch((error) => console.error("加载失败:", error));
3.3 进阶技巧:管理多个异步任务
通过 jQuery.when()
结合多个 Deferred 对象,可以实现“批量异步操作”的统一管理:
const deferred1 = jQuery.Deferred();
const deferred2 = jQuery.Deferred();
jQuery.when(
deferred1.promise(),
deferred2.promise()
).then(
(result1, result2) => {
console.log("两个任务均完成:", result1, result2);
}
);
// 模拟异步任务完成
setTimeout(() => deferred1.resolve("任务1完成"), 500);
setTimeout(() => deferred2.resolve("任务2完成"), 1000);
四、实际案例:构建可复用的异步模块
4.1 场景描述
假设需要开发一个工具函数,用于延迟执行某个操作(如等待用户输入),并允许外部订阅其结果:
class DelayedTask {
constructor(delayTime) {
this.deferred = jQuery.Deferred();
this.promise = this.deferred.promise();
setTimeout(() => {
this.deferred.resolve(`延迟 ${delayTime} 毫秒后完成`);
}, delayTime);
}
// 提供 Promise 接口
then(onFulfilled, onRejected) {
return this.promise.then(onFulfilled, onRejected);
}
}
// 使用示例
const task = new DelayedTask(2000);
task.then((result) => console.log(result)); // 2秒后输出结果
4.2 案例扩展:支持取消任务
通过 deferred.promise()
的封装,还可以实现任务的取消功能:
class CancellableTask {
constructor(delayTime) {
this.deferred = jQuery.Deferred();
this.promise = this.deferred.promise();
this.timeoutId = setTimeout(() => {
this.deferred.resolve("任务完成");
}, delayTime);
}
cancel() {
clearTimeout(this.timeoutId);
this.deferred.reject("任务被取消");
}
}
const task = new CancellableTask(3000);
task.promise.then(
(result) => console.log("成功:", result),
(error) => console.log("失败:", error)
);
// 1秒后取消任务
setTimeout(() => task.cancel(), 1000);
五、常见问题与注意事项
5.1 为什么需要区分 Deferred 和 Promise?
- 安全性:Promise 对象只提供监听接口,防止外部代码意外修改任务状态。
- 设计模式:遵循“封装”原则,确保模块职责分离。
5.2 deferred.promise() 的返回值类型
调用 deferred.promise()
后,返回的 Promise 对象是不可变的,即使后续修改 Deferred 的状态,Promise 仍能正确反映最新状态。
5.3 与原生 Promise 的兼容性
jQuery 的 Deferred 对象与 ES6 Promise 有相似的功能,但并非完全兼容。若需统一处理不同来源的 Promise,建议使用 jQuery.when()
或第三方库(如 es6-promise
)。
结论:用 deferred.promise() 简化异步开发
通过 jQuery deferred.promise()
方法,开发者可以:
- 清晰分离异步任务的控制与观察逻辑;
- 避免“回调地狱”,提升代码可维护性;
- 灵活管理复杂异步流程,如并行任务或条件分支。
无论是处理 AJAX 请求、封装自定义异步模块,还是协调多个任务的执行,deferred.promise()
都是 jQuery 异步编程的“瑞士军刀”。掌握这一工具,将帮助你在 Web 开发中更加得心应手。
通过本文的深入讲解,希望读者能够理解 jQuery deferred.promise() 方法 的核心原理,并在实际项目中灵活运用。异步编程的挑战远不止于此,但掌握这一工具,将为你的开发之路打下坚实的基础。