Promise
最近我一直在学习事件驱动模型和Ajax等组件。在这些组件中,经常会遇到异步操作。虽然在后端开发中,异步操作很常见,但是我作为前端新手,在学习前端时经常使用Ajax进行异步请求,而被其回调处理折磨得死去活来。幸好我遇到了Promise。
Promise 是一种处理异步操作的方式,它可以更好地管理异步结果,并支持链式调用,从而避免了多层嵌套的回调。
Promise对象概念
The
Promise
object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
Promise对象代表一个异步操作的最终结果以及其结果值,由于这个未来值还不确定,因此为其定义三个状态:
fulfilled
意味着这个操作成功rejected
意味着这个操作失败pending
初始状态, 既不是fulfilled
也不是rejected
的状态。
Promise的构造函数
new Promise(executor)
//上述代码等价于下面代码
new Promise((resolveFunc, rejectFunc)=>{
resloveFunc(value) //call on resolved, 同时会将状态转换为 fulfilled
rejectFunc(reason) // call on rejected 同时会将状态转换为 rejected
})
executor: 是一个 function。它接收两个函数作为参数:
resolveFunc
和rejectFunc
。在executor
中抛出的任何错误都会导致 Promise 被拒绝,并且返回值将被忽略。
使用案例
假设我们有三个异步操作,它们有先后顺序,前面的异步请求成功并返回响应之后才能调用下一个异步操作。下面将从传统方法和使用Promise来实现来处理这个逻辑。
在传统方法中,我们经常会在异步函数中参数中设置回调函数( Callback Function
),轻而易举写出了以下代码,多个异步操作需要依次执行,并且其中一个异步操作的结果会影响下一个异步操作时,就会导致回调函数嵌套的情况。
// eg.1
doSomethingAsync(function(result1) {
doSomethingElseAsync(result1, function(result2) {
doAnotherAsync(result2, function(result3) {
// 更多嵌套的异步操作
// ...
});
});
});
在上面的例子中,doSomethingAsync
函数返回一个异步结果,并在回调函数中处理该结果。然后, doSomethingElseAsync
函数依赖于第一个异步结果,并在嵌套的回调函数中处理第二个异步结果。这种嵌套的回调结构会导致代码的层次结构变得复杂,很难阅读和维护,从而形成回调地狱。如果以上问题使用Promise来解决,就变成了:
// eg.2
function doSomethingAsync() {
return new Promise((resolve, reject) => {
// 异步操作,例如网络请求、定时器等
// ...
// 异步操作完成后,调用 resolve 或 reject
resolve(result);
// 或
reject(error);
});
}
function doSomethingElseAsync(data) {
return new Promise((resolve, reject) => {
// 异步操作,例如网络请求、定时器等
// ...
// 异步操作完成后,调用 resolve 或 reject
resolve(result2);
// 或
reject(error2);
});
}
//Promise链式调用
doSomethingAsync()
.then(result1 => {
return doSomethingElseAsync(result1);
})
.then(result2 => {
return doAnotherAsync(result2);
})
.then(result3 => {
// 处理最终的结果
})
.catch(error => {
// 处理错误
});
在上述代码中,我们在 doSomethingAsync
中使用了Promise的链式调用,通过 .then()
来依次处理异步操作的结果,如果其中任何一个操作发生错误,可以使用 .catch()
来进行捕获和处理。后来,JS又加入了 async/await
语法,以便更舒适的使用 promise。
// eg.3
async function handleAsyncOperations() {
try {
const result1 = await doSomethingAsync();
const result2 = await doSomethingElseAsync(result1);
const result3 = await doAnotherAsync(result2);
// 处理最终的结果
} catch (error) {
// 处理错误
}
return result3;
}
handleAsyncOperations();
对于上述代码,有几点需要说明:
-
被async修饰的函数必须返回一个promise,如果返回的非promise类型,则会自动包装成一个promise类型
async function foo() { return 1; } //It is similar to: function foo() { return Promise.resolve(1); }
-
The
await
operator is used to wait for a[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
and get its fulfillment value. It can only be used inside an async function or at the top level of a module. -
await/async 可以帮助我们简化代码,无需太多的
then()
语句
关于promise
的更多内容,例如其原型方法then
、finally
、catch
以及常用方法resolve
等可以查看MDN官网。