Promise对象代表一个异步操作的最终完成(或失败)及其结果值。
Deferred对象是jQuery的异步任务管理器,可以创建并控制Promise的状态。
// 创建Deferred对象
var deferred = $.Deferred();
// 获取Promise对象
var promise = deferred.promise();
// 异步任务完成后调用resolve
function asyncTask() {
setTimeout(function() {
deferred.resolve("任务完成!");
}, 1000);
}
// 绑定回调函数
promise.done(function(message) {
console.log("成功:", message);
}).fail(function(error) {
console.log("失败:", error);
}).always(function() {
console.log("总是执行");
});
// 开始异步任务
asyncTask();
// 也可以直接创建已完成的Deferred
var resolvedDeferred = $.Deferred().resolve("立即完成");
var rejectedDeferred = $.Deferred().reject("立即拒绝");
// 进度通知
var progressDeferred = $.Deferred();
progressDeferred.progress(function(value) {
console.log("进度:", value + "%");
});
// 手动触发进度
progressDeferred.notify(50);
| 方法 | 描述 | 示例 |
|---|---|---|
resolve([args]) |
将Deferred状态设置为已完成 | deferred.resolve(data) |
resolveWith(context, [args]) |
指定上下文并完成 | deferred.resolveWith(this, [data]) |
reject([args]) |
将Deferred状态设置为已拒绝 | deferred.reject(error) |
rejectWith(context, [args]) |
指定上下文并拒绝 | deferred.rejectWith(this, [error]) |
notify([args]) |
触发进度回调 | deferred.notify(progress) |
promise([target]) |
返回Promise对象 | var promise = deferred.promise() |
state() |
获取当前状态 | deferred.state() // "pending"|"resolved"|"rejected" |
Promise对象是Deferred的只读版本,用于订阅异步操作的结果。
// 从Deferred获取Promise
var deferred = $.Deferred();
var promise = deferred.promise();
// 添加回调函数
promise.done(function(data) {
console.log("成功回调:", data);
});
promise.fail(function(error) {
console.log("失败回调:", error);
});
promise.always(function() {
console.log("总是执行");
});
promise.progress(function(value) {
console.log("进度更新:", value);
});
// 链式调用回调
promise
.done(function(data) {
console.log("第一步:", data);
return data + " -> 处理完成";
})
.done(function(data) {
console.log("第二步:", data);
});
// $.when() 创建Promise
var promise1 = $.Deferred().resolve("结果1").promise();
var promise2 = $.Deferred().resolve("结果2").promise();
$.when(promise1, promise2).done(function(result1, result2) {
console.log("所有Promise都完成:", result1, result2);
});
// 从现有值创建Promise
var resolvedPromise = $.when("立即完成的值");
resolvedPromise.done(function(value) {
console.log(value); // "立即完成的值"
});
// Promise状态检查
console.log(promise.state()); // "pending", "resolved", 或 "rejected"
// 包装AJAX请求
function getUserData(userId) {
var deferred = $.Deferred();
$.ajax({
url: '/api/users/' + userId,
method: 'GET'
}).done(function(data) {
deferred.resolve(data);
}).fail(function(error) {
deferred.reject(error);
});
return deferred.promise();
}
// 包装setTimeout
function delay(ms) {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve("等待了 " + ms + " 毫秒");
}, ms);
return deferred.promise();
}
// 包装事件
function onClickPromise(element) {
var deferred = $.Deferred();
$(element).one('click', function(event) {
deferred.resolve({
event: event,
element: this
});
});
return deferred.promise();
}
// 使用包装的函数
getUserData(123)
.done(function(user) {
console.log("用户数据:", user);
})
.fail(function(error) {
console.error("获取失败:", error);
});
delay(1000).done(function(message) {
console.log(message); // "等待了 1000 毫秒"
});
onClickPromise('#myButton').done(function(data) {
console.log("按钮被点击了:", data.element);
});
| 方法 | Deferred | Promise | 说明 |
|---|---|---|---|
| resolve/reject | 只有Deferred可以改变状态 | ||
| done/fail/always | 两者都可以添加回调 | ||
| promise() | Deferred返回Promise对象 | ||
| state() | 两者都可以检查状态 |
Promise支持链式调用,可以优雅地处理多个连续的异步操作。
// 基本链式调用
function asyncStep1() {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve("第一步完成");
}, 1000);
return deferred.promise();
}
function asyncStep2(data) {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve(data + " -> 第二步完成");
}, 1000);
return deferred.promise();
}
function asyncStep3(data) {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve(data + " -> 第三步完成");
}, 1000);
return deferred.promise();
}
// 链式调用
asyncStep1()
.then(function(result1) {
console.log(result1);
return asyncStep2(result1);
})
.then(function(result2) {
console.log(result2);
return asyncStep3(result2);
})
.then(function(result3) {
console.log("最终结果:", result3);
})
.fail(function(error) {
console.error("链式调用失败:", error);
});
// 使用pipe方法(jQuery 1.8之前)
asyncStep1()
.pipe(function(result1) {
return asyncStep2(result1);
})
.pipe(function(result2) {
return asyncStep3(result2);
})
.done(function(finalResult) {
console.log("pipe最终结果:", finalResult);
});
// 链式调用中的错误处理
function riskyStep() {
var deferred = $.Deferred();
setTimeout(function() {
if (Math.random() > 0.5) {
deferred.resolve("成功");
} else {
deferred.reject("随机失败");
}
}, 500);
return deferred.promise();
}
riskyStep()
.then(function(result) {
console.log("第一步成功:", result);
return "继续下一步";
})
.then(function(result) {
console.log("第二步:", result);
throw new Error("手动抛出错误");
})
.then(function(result) {
// 这里不会执行,因为上一步出错了
console.log("第三步:", result);
})
.fail(function(error) {
console.error("链式调用出错:", error);
})
.always(function() {
console.log("链式调用结束");
});
// 返回值的链式传递
$.Deferred().resolve(10)
.then(function(value) {
console.log("原始值:", value); // 10
return value * 2; // 返回新值
})
.then(function(value) {
console.log("两倍值:", value); // 20
return $.Deferred().resolve(value + 5).promise(); // 返回新的Promise
})
.then(function(value) {
console.log("最终值:", value); // 25
});
| 方法 | 描述 | 返回值 | 版本 |
|---|---|---|---|
.then() |
添加完成和失败回调,返回新Promise | Promise | jQuery 1.8+ |
.pipe() |
管道方法,类似then但参数不同 | Promise | jQuery 1.6-1.7(已弃用) |
.done() |
添加成功回调,不返回新Promise | 原始Promise | jQuery 1.5+ |
.fail() |
添加失败回调,不返回新Promise | 原始Promise | jQuery 1.5+ |
.then()方法进行链式调用,它返回一个新的Promise对象,可以实现真正的链式操作。
使用$.when()方法可以并行处理多个异步操作,等待所有操作完成。
// 基本并行处理
function fetchUserData() {
return $.Deferred().resolve("用户数据").promise();
}
function fetchProductData() {
return $.Deferred().resolve("产品数据").promise();
}
function fetchOrderData() {
return $.Deferred().resolve("订单数据").promise();
}
// 等待所有Promise完成
$.when(
fetchUserData(),
fetchProductData(),
fetchOrderData()
).done(function(userData, productData, orderData) {
console.log("所有数据获取完成:");
console.log("用户:", userData);
console.log("产品:", productData);
console.log("订单:", orderData);
// 处理所有数据
processAllData(userData, productData, orderData);
}).fail(function(error) {
console.error("某个请求失败:", error);
});
// 动态数量的并行请求
function fetchMultipleItems(itemIds) {
var promises = [];
itemIds.forEach(function(id) {
var promise = $.ajax({
url: '/api/items/' + id,
method: 'GET'
});
promises.push(promise);
});
// 使用apply将数组作为参数传递
return $.when.apply($, promises);
}
fetchMultipleItems([1, 2, 3, 4, 5])
.done(function() {
// arguments包含所有请求的结果
console.log("所有项目获取完成");
for(var i = 0; i < arguments.length; i++) {
console.log("项目" + (i+1) + ":", arguments[i]);
}
});
// 部分成功处理
function createPartialSuccessHandler() {
var successes = [];
var failures = [];
return {
done: function(callback) {
successes.push(callback);
return this;
},
fail: function(callback) {
failures.push(callback);
return this;
},
execute: function() {
successes.forEach(function(callback) {
callback();
});
failures.forEach(function(callback) {
callback();
});
}
};
}
// 使用$.when处理部分失败
var promise1 = $.Deferred().resolve("成功1").promise();
var promise2 = $.Deferred().reject("失败2").promise();
var promise3 = $.Deferred().resolve("成功3").promise();
$.when(promise1, promise2, promise3)
.done(function() {
console.log("所有都成功(这里不会执行)");
})
.fail(function(error) {
console.log("有任务失败:", error); // 输出:有任务失败: 失败2
});
// 并行与串行结合
function complexWorkflow() {
// 第一步:并行获取数据
return $.when(
fetchUserProfile(),
fetchUserSettings()
).then(function(profile, settings) {
// 第二步:串行处理数据
return processProfileAndSettings(profile, settings);
}).then(function(processedData) {
// 第三步:并行保存到不同地方
return $.when(
saveToDatabase(processedData),
saveToCloud(processedData)
);
});
}
// 带超时的并行处理
function fetchWithTimeout(url, timeout) {
var deferred = $.Deferred();
// 创建超时Promise
var timeoutPromise = $.Deferred();
setTimeout(function() {
timeoutPromise.reject(new Error("请求超时"));
}, timeout);
// 创建请求Promise
var requestPromise = $.ajax({ url: url });
// 使用$.when竞争
$.when(requestPromise, timeoutPromise)
.done(function(data) {
deferred.resolve(data);
})
.fail(function(error) {
deferred.reject(error);
});
return deferred.promise();
}
// 所有任务都必须成功
$.when(task1, task2, task3)
.done(function(r1, r2, r3) {
// 所有任务都成功
})
.fail(function(error) {
// 任意任务失败
});
// 任意任务成功即可
$.Deferred(function(deferred) {
var success = false;
$.when(task1, task2, task3)
.done(function() {
if (!success) {
success = true;
deferred.resolve(arguments);
}
})
.fail(function() {
// 继续等待其他任务
});
}).promise();
Promise提供了统一的错误处理机制,可以优雅地捕获和处理异步操作中的异常。
// 基本错误处理
function riskyOperation() {
var deferred = $.Deferred();
setTimeout(function() {
try {
// 模拟可能出错的操作
if (Math.random() > 0.7) {
throw new Error("随机错误");
}
deferred.resolve("操作成功");
} catch (error) {
deferred.reject(error);
}
}, 1000);
return deferred.promise();
}
riskyOperation()
.done(function(result) {
console.log("成功:", result);
})
.fail(function(error) {
console.error("失败:", error.message);
})
.always(function() {
console.log("操作完成(无论成功失败)");
});
// 链式调用中的错误传播
function step1() {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve("第一步");
}, 500);
return deferred.promise();
}
function step2(data) {
var deferred = $.Deferred();
setTimeout(function() {
if (data === "第一步") {
deferred.reject(new Error("第二步失败"));
} else {
deferred.resolve(data + " -> 第二步");
}
}, 500);
return deferred.promise();
}
step1()
.then(step2)
.then(function(result) {
console.log("成功:", result);
})
.fail(function(error) {
console.error("链式调用失败:", error.message);
// 错误会一直传播到第一个fail回调
});
// 错误恢复(catch和recover)
function fetchData() {
return $.Deferred().reject(new Error("数据源失败")).promise();
}
function getFallbackData() {
return $.Deferred().resolve("备用数据").promise();
}
// 尝试主数据源,失败时使用备用数据
fetchData()
.fail(function(error) {
console.warn("主数据源失败:", error.message);
return getFallbackData(); // 返回新的Promise
})
.done(function(data) {
console.log("最终数据:", data); // "备用数据"
});
// 统一错误处理函数
function handleAPIError(error) {
console.error("API错误:", error);
// 根据错误类型采取不同措施
if (error.status === 401) {
// 未授权,跳转到登录页
window.location.href = '/login';
} else if (error.status === 404) {
// 资源不存在
showToast("请求的资源不存在");
} else if (error.status === 500) {
// 服务器错误
showToast("服务器内部错误,请稍后重试");
} else {
// 其他错误
showToast("网络请求失败: " + error.message);
}
// 返回一个rejected promise继续传播错误
return $.Deferred().reject(error).promise();
}
// 使用统一错误处理
$.ajax({
url: '/api/data',
method: 'GET'
})
.fail(handleAPIError)
.done(function(data) {
console.log("数据:", data);
});
// 超时错误处理
function withTimeout(promise, timeoutMs) {
var deferred = $.Deferred();
// 创建超时Promise
var timeoutPromise = $.Deferred();
setTimeout(function() {
timeoutPromise.reject(new Error("操作超时 (" + timeoutMs + "ms)"));
}, timeoutMs);
// 竞争:请求 vs 超时
$.when(promise, timeoutPromise)
.done(function(data) {
deferred.resolve(data);
})
.fail(function(error) {
deferred.reject(error);
});
return deferred.promise();
}
// 使用超时包装
var apiPromise = $.ajax({ url: '/api/slow' });
withTimeout(apiPromise, 5000)
.done(function(data) {
console.log("数据:", data);
})
.fail(function(error) {
console.error("失败:", error.message);
});
// 全局Promise错误处理
$(document).ajaxError(function(event, jqxhr, settings, error) {
console.error("全局AJAX错误:", error);
});
// 使用always进行清理工作
function loadResource(url) {
var deferred = $.Deferred();
var isLoading = true;
$.ajax({
url: url,
method: 'GET'
})
.done(function(data) {
deferred.resolve(data);
})
.fail(function(error) {
deferred.reject(error);
})
.always(function() {
isLoading = false;
console.log("资源加载完成,清理工作");
});
return deferred.promise();
}
.fail()回调处理未捕获的错误.always()进行清理工作,无论成功失败都会执行了解jQuery Deferred/Promise与ES6 Promise的异同,以及如何进行互操作。
| 特性 | jQuery Deferred/Promise | ES6 Promise |
|---|---|---|
| 创建方式 | $.Deferred() |
new Promise() |
| 状态变更 | 通过resolve()/reject()方法 |
通过执行器函数参数 |
| 链式调用 | .then(), .done(), .fail() |
.then(), .catch() |
| 进度通知 | .progress(), .notify() |
不支持 |
| 并行处理 | $.when() |
Promise.all(), Promise.race() |
| 错误传播 | 需要显式调用.fail() |
自动传播到.catch() |
| 返回值 | .then()返回新Promise |
.then()返回新Promise |
// 将jQuery Promise转换为ES6 Promise
function jQueryToES6Promise(jqPromise) {
return new Promise(function(resolve, reject) {
jqPromise
.done(resolve)
.fail(reject);
});
}
// 将ES6 Promise转换为jQuery Promise
function ES6TojQueryPromise(es6Promise) {
var deferred = $.Deferred();
es6Promise
.then(function(value) {
deferred.resolve(value);
})
.catch(function(error) {
deferred.reject(error);
});
return deferred.promise();
}
// 混合使用示例
function mixedPromiseWorkflow() {
// jQuery Promise
var jqPromise = $.ajax({
url: '/api/data',
method: 'GET'
});
// ES6 Promise
var es6Promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve("ES6 Promise完成");
}, 1000);
});
// 转换为统一格式
var es6FromJQ = jQueryToES6Promise(jqPromise);
var jqFromES6 = ES6TojQueryPromise(es6Promise);
// 使用ES6 Promise.all
return Promise.all([es6FromJQ, es6Promise])
.then(function(results) {
console.log("ES6 Promise.all完成:", results);
return results;
});
}
// 使用$.when处理混合Promise
function mixedWithWhen() {
var jqPromise = $.Deferred().resolve("jQuery结果").promise();
var es6Promise = Promise.resolve("ES6结果");
// 将ES6 Promise转换为jQuery Promise
var jqFromES6 = ES6TojQueryPromise(es6Promise);
return $.when(jqPromise, jqFromES6)
.done(function(result1, result2) {
console.log("两个都完成:", result1, result2);
});
}
// 现代化转换函数
function adaptToES6(jqPromise) {
// 如果已经是ES6 Promise,直接返回
if (jqPromise instanceof Promise) {
return jqPromise;
}
// 转换jQuery Promise
return new Promise(function(resolve, reject) {
if (jqPromise.state && jqPromise.state() === 'resolved') {
resolve(jqPromise.result);
} else if (jqPromise.state && jqPromise.state() === 'rejected') {
reject(jqPromise.result);
} else {
jqPromise.then(resolve, reject);
}
});
}
// 使用示例
var jqDeferred = $.Deferred();
setTimeout(function() {
jqDeferred.resolve("jQuery延迟对象");
}, 500);
adaptToES6(jqDeferred.promise())
.then(function(result) {
console.log("转换为ES6 Promise:", result);
})
.catch(function(error) {
console.error("错误:", error);
});
// 批量转换
function convertAllToES6(promises) {
return promises.map(function(promise) {
if (promise.then && promise.done && promise.fail) {
// jQuery Promise
return adaptToES6(promise);
} else if (promise instanceof Promise) {
// 已经是ES6 Promise
return promise;
} else {
// 其他值,包装为ES6 Promise
return Promise.resolve(promise);
}
});
}
// 现代化建议
function modernAsyncWorkflow() {
// 如果支持ES6 Promise,优先使用
if (typeof Promise !== 'undefined') {
return new Promise(function(resolve, reject) {
// 异步操作
setTimeout(function() {
resolve("现代Promise");
}, 1000);
});
} else {
// 回退到jQuery Promise
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve("jQuery Promise");
}, 1000);
return deferred.promise();
}
}
.done()/.fail()替换为.then()Promise.all()和Promise.race()
// 使用async/await处理jQuery Promise
async function fetchDataWithJQuery() {
try {
// jQuery AJAX返回的是jQuery Promise
const data = await $.ajax({
url: '/api/data',
method: 'GET'
});
console.log("数据:", data);
return data;
} catch (error) {
console.error("获取失败:", error);
throw error;
}
}
// 将jQuery Deferred转换为async/await可用
function createAsyncDeferred() {
const deferred = $.Deferred();
// 为Deferred添加async支持
deferred.async = async function() {
return new Promise((resolve, reject) => {
this.then(resolve, reject);
});
};
return deferred;
}
// 使用示例
async function example() {
const deferred = createAsyncDeferred();
setTimeout(() => {
deferred.resolve("异步结果");
}, 1000);
const result = await deferred.async();
console.log("结果:", result);
}
使用Promise链式调用实现一个天气预报应用。
| 概念 | 描述 | 示例方法 | 使用场景 |
|---|---|---|---|
| Deferred | 可写的Promise,可以改变状态 | resolve(), reject() |
创建自定义异步操作 |
| Promise | 只读的异步结果容器 | done(), fail() |
订阅异步操作结果 |
| 链式调用 | 多个异步操作顺序执行 | then() |
依赖前一步结果的异步流程 |
| 并行处理 | 多个异步操作同时执行 | $.when() |
不相关的多个异步任务 |
| 错误传播 | 错误沿Promise链传递 | fail() |
统一错误处理 |
| 进度通知 | 异步操作进度更新 | progress() |
长时间操作的进度反馈 |