主页/jQuery教程/回调、延迟与异步/jQuery将动画、Ajax转化为Promise

jQuery将动画、Ajax转化为Promise

4,662字
20–30 分钟

概览

目录

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 元素的动画队列(包括 fadeInanimatefadeOut)全部完成后才触发 .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.0slim 构建版本 移除 Deferred 模块。但 Ajax 返回的 jqXHR 仍是一个“thenable”对象,可以配合原生 Promise 使用。完整版保留所有功能。

浏览器兼容性

将 Ajax 转化为 Promise将动画转化为 Promise 的兼容性与 jQuery 核心库保持一致。

浏览器最低支持版本 (jQuery 3.x/4.x 完整版)
Chrome30+
Edge12+
Firefox25+
Opera18+
Safari7+
Chrome Android30+
Firefox for Android25+
Opera Android18+
Safari on iOS7+
Samsung Internet4.0+
WebView Android4.4+
WebView on iOS7+

注:对于使用 jQuery 4.0 slim 构建版本的项目,由于移除了 Deferred 模块,.promise() 方法将不可用,但 $.ajax() 返回的 jqXHR 对象仍然是一个“thenable”对象(具有 .then() 方法),可以配合原生 Promise 使用,例如 Promise.resolve($.ajax(...)).then(...)

掌握 jQuery 将动画、Ajax 转化为 Promise 的技术,是迈向现代化、高效 jQuery 异步编程的关键一步。它不仅统一了不同异步操作的处理模式,也为代码向原生 Promise 的平滑迁移铺平了道路。无论是处理复杂的依赖请求序列,还是协调精美的页面交互动画,Promise 模式都提供了清晰、强大的控制力。