jQuery 延迟对象与Promise

延迟对象 (Deferred)

jQuery的Deferred对象是一种异步编程模式,用于处理异步操作。它提供了一种优雅的方式来处理回调函数,使代码更加清晰和可维护。

// 创建延迟对象 var deferred = $.Deferred(); // 异步操作 setTimeout(function() { var success = true; if (success) { deferred.resolve('操作成功'); } else { deferred.reject('操作失败'); } }, 1000); // 处理结果 deferred.done(function(result) { console.log('成功:', result); }).fail(function(error) { console.error('失败:', error); }).always(function() { console.log('操作完成'); });

Promise

Promise是Deferred对象的一个只读视图,它只提供了添加回调函数的方法,而不提供触发回调的方法。

// 创建延迟对象并返回Promise function asyncOperation() { var deferred = $.Deferred(); setTimeout(function() { deferred.resolve('操作成功'); }, 1000); return deferred.promise(); } // 使用Promise var promise = asyncOperation(); promise.done(function(result) { console.log('成功:', result); }); // 链式调用 asyncOperation() .done(function(result) { console.log('第一步成功:', result); return anotherAsyncOperation(); }) .done(function(result) { console.log('第二步成功:', result); }) .fail(function(error) { console.error('失败:', error); });

Promise的高级用法

// 并行执行多个异步操作 $.when( asyncOperation1(), asyncOperation2(), asyncOperation3() ).done(function(result1, result2, result3) { console.log('所有操作成功:', result1, result2, result3); }).fail(function(error) { console.error('至少有一个操作失败:', error); }); // 转换普通对象为Promise var promise = $.when('普通值'); promise.done(function(value) { console.log('值:', value); }); // 处理AJAX请求 $.ajax({ url: 'data.json', dataType: 'json' }).done(function(data) { console.log('数据:', data); }).fail(function() { console.error('请求失败'); });

自定义事件

创建和触发自定义事件

jQuery允许我们创建和触发自定义事件,这对于组件间通信非常有用。

// 绑定自定义事件 $('#element').on('customEvent', function(event, data) { console.log('自定义事件触发:', data); }); // 触发自定义事件 $('#element').trigger('customEvent', { message: 'Hello World' }); // 使用命名空间 $('#element').on('customEvent.namespace1', function() { console.log('命名空间1的事件'); }); $('#element').on('customEvent.namespace2', function() { console.log('命名空间2的事件'); }); // 只触发特定命名空间的事件 $('#element').trigger('customEvent.namespace1'); // 移除特定命名空间的事件 $('#element').off('.namespace1');

事件委托和自定义事件

// 使用事件委托处理自定义事件 $('#container').on('itemAdded', '.item', function(event, itemData) { console.log('项目添加:', itemData); }); // 触发事件 $('.item').trigger('itemAdded', { id: 1, name: '项目1' }); // 自定义事件的冒泡 $('div').on('customEvent', function(event) { console.log('事件触发在:', this.tagName); // 阻止冒泡 // event.stopPropagation(); }); // 触发事件 $('span').trigger('customEvent');

动画队列

动画队列的基本概念

jQuery的动画队列允许我们按顺序执行多个动画,而不需要嵌套回调函数。

// 动画队列 $('#box') .animate({ left: '100px' }, 1000) .animate({ top: '100px' }, 1000) .animate({ width: '200px' }, 1000) .animate({ height: '200px' }, 1000) .animate({ opacity: 0.5 }, 1000); // 自定义队列 $('#element') .queue('custom', function(next) { console.log('第一步'); next(); // 执行下一个队列项 }) .queue('custom', function(next) { console.log('第二步'); next(); }) .queue('custom', function(next) { console.log('第三步'); next(); }) .dequeue('custom'); // 开始执行队列 // 清除队列 $('#element').stop(true); // 清除所有队列项 // 跳转到队列末尾 $('#element').finish(); // 立即完成所有队列中的动画

模块化开发

使用立即执行函数表达式 (IIFE)

// 模块化组织代码 var myModule = (function($) { // 私有变量 var privateVar = '私有变量'; // 私有方法 function privateMethod() { console.log('私有方法', privateVar); } // 公共接口 return { publicVar: '公共变量', publicMethod: function() { console.log('公共方法'); privateMethod(); }, init: function() { console.log('模块初始化'); } }; })(jQuery); // 使用模块 myModule.init(); myModule.publicMethod(); console.log(myModule.publicVar);

使用jQuery的data方法存储数据

// 使用data方法存储数据 $('#element').data('user', { id: 1, name: '张三', email: 'zhangsan@example.com' }); // 获取数据 var user = $('#element').data('user'); console.log(user.name); // 输出: 张三 // 存储方法 $('#element').data('methods', { show: function() { console.log('显示元素'); }, hide: function() { console.log('隐藏元素'); } }); // 调用方法 $('#element').data('methods').show();

实践案例:TODO应用

在这个案例中,我们将创建一个完整的TODO应用,应用前面学习的高级特性。

// TODO应用 var TodoApp = (function($) { // 私有变量 var $todoInput, $addButton, $todoList; var todos = []; // 初始化 function init() { // 缓存DOM元素 $todoInput = $('#todo-input'); $addButton = $('#add-todo'); $todoList = $('#todo-list'); // 绑定事件 bindEvents(); // 加载本地存储的TODO项 loadTodos(); // 渲染TODO列表 renderTodos(); } // 绑定事件 function bindEvents() { $addButton.on('click', addTodo); $todoInput.on('keypress', function(e) { if (e.which === 13) { // 回车键 addTodo(); } }); // 使用事件委托处理删除和完成事件 $todoList.on('click', '.delete', deleteTodo); $todoList.on('click', '.toggle', toggleTodo); } // 添加TODO项 function addTodo() { var text = $todoInput.val().trim(); if (text) { var todo = { id: Date.now(), text: text, completed: false }; todos.push(todo); saveTodos(); renderTodos(); $todoInput.val(''); // 触发自定义事件 $(document).trigger('todoAdded', todo); } } // 删除TODO项 function deleteTodo() { var id = parseInt($(this).closest('li').data('id')); todos = todos.filter(function(todo) { return todo.id !== id; }); saveTodos(); renderTodos(); // 触发自定义事件 $(document).trigger('todoDeleted', id); } // 切换TODO项状态 function toggleTodo() { var id = parseInt($(this).closest('li').data('id')); var todo = todos.find(function(todo) { return todo.id === id; }); if (todo) { todo.completed = !todo.completed; saveTodos(); renderTodos(); // 触发自定义事件 $(document).trigger('todoToggled', todo); } } // 渲染TODO列表 function renderTodos() { $todoList.empty(); todos.forEach(function(todo) { var $li = $('
  • ') .data('id', todo.id) .addClass(todo.completed ? 'completed' : ''); var $toggle = $(''); var $text = $('' + todo.text + ''); var $delete = $(''); var $actions = $('
    ') .append($toggle) .append($delete); $li.append($text).append($actions); $todoList.append($li); }); } // 保存TODO项到本地存储 function saveTodos() { localStorage.setItem('todos', JSON.stringify(todos)); } // 从本地存储加载TODO项 function loadTodos() { var storedTodos = localStorage.getItem('todos'); if (storedTodos) { todos = JSON.parse(storedTodos); } } // 公共接口 return { init: init, getTodos: function() { return todos; } }; })(jQuery); // 初始化应用 $(document).ready(function() { TodoApp.init(); // 监听自定义事件 $(document).on('todoAdded', function(event, todo) { console.log('TODO添加:', todo); }); $(document).on('todoDeleted', function(event, id) { console.log('TODO删除:', id); }); $(document).on('todoToggled', function(event, todo) { console.log('TODO状态改变:', todo); }); });

    尝试使用以下TODO应用:

      互动练习:动画队列挑战

      在这个练习中,你需要使用jQuery的动画队列创建一个复杂的动画效果。

      推荐教程

      jQuery 基础概念

      学习jQuery的基本概念、安装方法和基本语法

      查看教程 →
      jQuery 选择器

      掌握jQuery的各种选择器用法

      查看教程 →
      jQuery DOM操作

      学习如何使用jQuery操作DOM元素

      查看教程 →
      jQuery 事件处理

      掌握jQuery的事件处理机制

      查看教程 →
      jQuery 动画效果

      学习如何使用jQuery创建动画效果

      查看教程 →
      jQuery AJAX

      学习如何使用jQuery简化AJAX请求

      查看教程 →