概览
jQuery 将 Ajax 转化为 Promise 是其异步编程模型的一次革命性升级,自 1.5 版本起,$.ajax() 返回的 jqXHR 对象便实现了 Promise 接口。而对于动画,jQuery 提供了 .promise() 方法,允许在特定集合的动画队列完成后获得一个 Promise 对象。将这两种核心操作 转化为 Promise,使得开发者能够使用统一的、可链式调用的模式来处理异步任务,摆脱了传统的回调嵌套,极大地提升了代码的可读性和可维护性。
将 Ajax 转化为 Promise
jQuery 的 Ajax 模块是与 Promise 结合最紧密的部分。从 jQuery 1.5 开始,$.ajax() 及其便捷方法(如 $.get()、$.post())返回的对象(jqXHR)就实现了 Promise 接口,这意味着它可以像 Deferred 对象一样被操作。
语法与使用
$.ajax() 返回的 jqXHR 对象支持以下 Promise 方法:
.done():请求成功时执行。.fail():请求失败时执行。.always():请求完成(无论成功或失败)时执行。.then():可以链式处理成功和失败的回调,并可进行结果转换。
示例:使用 Promise 风格的 Ajax 请求
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ajax 转化为 Promise</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
</head>
<body>
<button id="loadData">加载用户数据</button>
<div id="result"></div>
<script>
$('#loadData').on('click', function() {
var $result = $('#result');
$result.html('加载中...');
// $.ajax() 返回一个 Promise 对象
var requestPromise = $.ajax({
url: 'https://api.github.com/users/octocat',
dataType: 'json'
});
// 使用 Promise 方法处理结果
requestPromise
.done(function(data) {
var html = '<h3>' + data.name + '</h3>' +
'<p>粉丝数: ' + data.followers + '</p>' +
'<img src="' + data.avatar_url + '" width="100">';
$result.html(html);
})
.fail(function(jqXHR, textStatus) {
$result.html('<p style="color:red;">请求失败: ' + textStatus + '</p>');
})
.always(function() {
console.log('Ajax 请求已完成 (always)');
});
});
</script>
</body>
</html>此示例清晰地展示了 $.ajax() 返回的对象如何直接使用 .done()、.fail() 和 .always() 方法。这种 将 Ajax 转化为 Promise 的写法,使得异步请求的处理逻辑更加线性化和易于管理。
链式调用与结果转换
Promise 的另一个强大之处在于可以使用 .then() 进行链式调用,并在每次调用中转换结果。
$.ajax({
url: '/api/user/123',
dataType: 'json'
})
.then(function(user) {
// 第一个请求成功,根据返回的用户信息发起第二个请求
return $.ajax({
url: '/api/posts?userId=' + user.id,
dataType: 'json'
});
})
.then(function(posts) {
// 处理第二个请求返回的文章数据
console.log('用户文章:', posts);
})
.fail(function() {
// 任何一个请求失败都会进入这里
console.error('请求链中发生错误');
});在这个链式调用中,如果第一个请求失败,整个链会直接跳转到 .fail();如果成功,则自动将结果传递给下一个 .then()。这完美解决了“回调地狱”问题,是 jQuery 将 Ajax 转化为 Promise 的核心优势。
将动画转化为 Promise
动画同样是异步操作。jQuery 提供了 .promise() 方法,用于在特定元素集合上的所有动画(或其他排队的操作)完成后获得一个 Promise 对象。
.promise() 方法详解
语法
.promise( [queueName ] [, target ] )- queueName(可选):一个字符串,代表要观察的队列名称。默认为
"fx",即标准的动画队列。 - target(可选):一个对象,Promise 的方法将被合并到这个对象上。
当指定队列中的所有项目(包括延迟对象)都完成时,返回的 Promise 将被 resolved。
示例:等待一组动画完成
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>动画转化为 Promise</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
.box { width: 100px; height: 100px; background: #3498db; margin: 20px; display: none; float: left; }
.clear { clear: both; }
</style>
</head>
<body>
<button id="startAnim">开始动画序列</button>
<button id="logStatus" disabled>检查状态</button>
<div class="clear"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<script>
var $boxes = $('.box');
$('#startAnim').on('click', function() {
var $btn = $(this);
$btn.prop('disabled', true);
$('#logStatus').prop('disabled', true).text('动画执行中...');
// 启动一组动画
$boxes.each(function(index) {
$(this).delay(index * 300).fadeIn(800).animate({
width: '200px',
height: '200px'
}, 500).fadeOut(500);
});
// 获取所有动画的 Promise
var animationPromise = $boxes.promise();
// 当所有动画完成后执行
animationPromise.done(function() {
$btn.prop('disabled', false);
$('#logStatus').prop('disabled', false).text('所有动画已完成');
console.log('所有盒子动画执行完毕');
});
});
$('#logStatus').on('click', function() {
alert($(this).text());
});
</script>
</body>
</html>在这个示例中,.promise() 方法返回的 Promise 对象 在所有 .box 元素的动画队列(包括 fadeIn、animate 和 fadeOut)全部完成后才触发 .done() 回调。这使得 jQuery 将动画转化为 Promise 后,可以轻松地在复杂动画序列结束后执行清理或后续逻辑。
结合 $.when() 使用
动画的 Promise 同样可以与 $.when() 结合,用于协调多个独立的动画集合或其他异步任务。
var promise1 = $('#element1').slideUp(1000).promise();
var promise2 = $('#element2').fadeIn(800).promise();
$.when(promise1, promise2).done(function() {
console.log('元素1的滑动和元素2的淡入都已完成');
});两种转化方式的对比
下表总结了 jQuery 将 Ajax 转化为 Promise 和 将动画转化为 Promise 的特点。
| 特性 | 将 Ajax 转化为 Promise | 将动画转化为 Promise |
|---|---|---|
| 核心方法 | $.ajax() 及其便捷方法直接返回 jqXHR (Promise) | .promise() 方法 |
| 触发 resolved 的条件 | HTTP 请求成功完成 | 指定元素上的动画队列全部执行完毕 |
| 主要用途 | 处理异步数据请求,链式调用避免回调地狱 | 在多个元素动画完成后执行回调,协调复杂动画 |
| 返回对象 | jqXHR 对象(实现了 Promise 接口) | 一个普通的 Promise 对象 |
| 错误处理 | 通过 .fail() 捕获 HTTP 错误 | 动画通常不会“失败”,但可通过 .always() 执行收尾 |
| 进度通知 | 不支持(但可通过旧版 xhr 属性实现) | 不支持 |
版本变更记录
| 版本 | 变更内容 |
|---|---|
| 1.5 | 引入 $.ajax() 返回 jqXHR 对象,实现 Promise 接口。引入 .promise() 方法。 |
| 1.6 | 增强 .promise() 方法,允许指定不同队列。 |
| 1.8 | .then() 方法的行为被标准化,以更接近 Promise/A+ 规范。 |
| 3.0 | 正式弃用 jqXHR.success()、.error()、.complete(),推荐使用 Promise 风格方法。 |
| 4.0 | slim 构建版本 移除 Deferred 模块。但 Ajax 返回的 jqXHR 仍是一个“thenable”对象,可以配合原生 Promise 使用。完整版保留所有功能。 |
浏览器兼容性
将 Ajax 转化为 Promise 和 将动画转化为 Promise 的兼容性与 jQuery 核心库保持一致。
| 浏览器 | 最低支持版本 (jQuery 3.x/4.x 完整版) |
|---|---|
| Chrome | 30+ |
| Edge | 12+ |
| Firefox | 25+ |
| Opera | 18+ |
| Safari | 7+ |
| Chrome Android | 30+ |
| Firefox for Android | 25+ |
| Opera Android | 18+ |
| Safari on iOS | 7+ |
| Samsung Internet | 4.0+ |
| WebView Android | 4.4+ |
| WebView on iOS | 7+ |
注:对于使用 jQuery 4.0 slim 构建版本的项目,由于移除了 Deferred 模块,
.promise()方法将不可用,但$.ajax()返回的 jqXHR 对象仍然是一个“thenable”对象(具有.then()方法),可以配合原生 Promise 使用,例如Promise.resolve($.ajax(...)).then(...)。
掌握 jQuery 将动画、Ajax 转化为 Promise 的技术,是迈向现代化、高效 jQuery 异步编程的关键一步。它不仅统一了不同异步操作的处理模式,也为代码向原生 Promise 的平滑迁移铺平了道路。无论是处理复杂的依赖请求序列,还是协调精美的页面交互动画,Promise 模式都提供了清晰、强大的控制力。
