简介:JavaScript中的Promise对象是随着ES6(ECMAScript 2015)规范发布的,它是异步编程中的一种解决方案或者规范,解决了回调地狱的问题。它本质上是一个构造函数,可以实例化一个对象,从中获取异步操作的最终状态,使得异步代码可以像同步代码一样进行链式调用,从而提高代码的可读性和可维护性。
一、Promise的状态、方法,以及应用场景
在JavaScript中,Promise是一种强大的工具,用于处理异步操作。它提供了一种统一的接口,使得异步代码可以像同步代码一样进行链式调用,并且具有更好的错误处理机制。Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),同时,Promise也提供了两个用于改变状态的方法:resolve和reject,以及.then、.catch、.finally方法。
1. Promise的状态
- pending(进行中):这是Promise的初始状态,既不是成功也不是失败。
- fulfilled(已成功):这意味着操作成功完成。一旦Promise进入此状态,就不会再改变。
- rejected(已失败):这意味着操作失败。与fulfilled状态一样,一旦进入此状态,就不会再改变。
2. 改变Promise状态的方法
- resolve(value):将Promise的状态从pending变为fulfilled,并将value作为成功的结果。
- reject(reason):将Promise的状态从pending变为rejected,并将reason作为失败的原因。
3. Promise的方法
- .then(onFulfilled, onRejected):返回一个新的Promise,当原Promise状态变为fulfilled时,调用onFulfilled函数;当原Promise状态变为rejected时,调用onRejected函数。
- .catch(onRejected):是.then(null, onRejected)的简写,用于指定一个拒绝状态的回调函数。
- .finally(onFinally):无论Promise的状态如何,都会执行onFinally函数。
4. 应用场景与实例
场景1:Promise的执行顺序
(1)、Promise即是一个同步任务也是一个微任务,只有在执行了resolve或者reject后,才会执行.then或者.catch操作,变成微任务。
// Promise的执行顺序
let myPromise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
// resolve();
// reject();
})
myPromise.then(() => {
console.log(3);
}).catch(() => {
console.log(4);
}).finally(() => {
console.log(5);
})
console.log(6);
//控制台输出1 2 6,不会走.then .catch .finally方法,
//因为没有执行resolve() 或者 reject()方法
let myPromise2 = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
resolve();
// reject();
})
myPromise.then(() => {
console.log(3);
}).catch(() => {
console.log(4);
}).finally(() => {
console.log(5);
})
console.log(6);
//控制台输出1 2 6 3 5,因为执行了resolve()方法
场景2:异步操作
(2)、假设我们有一个异步函数fetchData()
,用于从服务器获取数据,这时使用Promise可以更方便地处理这个异步操作。
// 模拟异步操作
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟成功获取数据
resolve('成功获取数据');
// 或者模拟失败
// reject('获取数据失败');
}, 1000);
});
}
// 使用.then处理成功结果,使用.catch处理失败结果
fetchData()
.then(data => {
console.log(data); // 输出:成功获取数据
})
.catch(error => {
console.error(error); // 如果reject被调用,则会执行这里
});
场景3:错误处理
(3)、Promise允许我们更优雅地处理错误,通过.catch
方法,我们可以捕获Promise链中任何地方的错误。
function PromiseError() {
return new Promise((resolve, reject) => {
reject('发生错误');
});
}
PromiseError()
.then(result => {
console.log(result);
})
.catch(error => {
console.error('捕获到错误:', error); // 输出:捕获到错误: 发生错误
});
场景4:链式调用
(4)、Promise允许我们进行链式调用,这使得代码更加清晰和易于维护。
function promise1() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('promise1的结果'), 1000);
});
}
function promise2(value) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`promise2的结果:${value}`), 1000);
});
}
promise1()
.then(result => {
console.log(result); // 输出:promise1的结果
return promise2(result);
})
.then(result => {
console.log(result); // 输出:promise2的结果:promise1的结果
})
.catch(error => {
console.error('发生错误:', error);
});
场景5:使用.finally进行清理
(5)、无论Promise的状态如何,.finally
方法都会执行。这可以用于进行资源清理或执行一些必须的操作。
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('操作成功'), 1000);
});
}
myPromise()
.then(result => {
console.log(result); // 输出:操作成功
})
.catch(error => {
console.error('发生错误:', error);
})
.finally(() => {
console.log('无论成功还是失败,都会执行这里。'); // 总是输出这句话
})
小结:
-
Promise 有三种状态(pending、fulfilled、rejected)和两个方法(resolve、reject)共同构成了异步操作处理的核心机制;
-
通过调用 resolve 和 reject 来改变 Promise 的状态,最后通过 then、catch 、finally等方法来处理这些状态及其结果;
-
Promise即是一个同步任务也是一个微任务,它会首先执行自身的同步任务,只有在执行了resolve或者reject后,才会执行.then或者.catch操作,变成微任务。
5. Promise在执行了reslove或者reject后,如果后续有.then、.catch、箭头函数时,会直接执行箭头函数。
二. Promise.all方法
1. 方法详细
-
Promise.all是一种用于处理多个Promise对象的方法,该方法接收一个数组作为参数,并返回一个新的Promise对象。这个对象会在所有Promise对象都成功解析后解析,解析的结果是一个数组,包含了所有Promise对象解析后的结果。
-
解析时如果任何一个Promise对象失败,则这个新的Promise对象会立即失败,并返回第一个失败的Promise对象的错误信息。
-
Promise.all不会改变原有的Promise对象的状态,原有的 Promise 对象仍会按照自己的状态(fulfilled或rejected)进行解析。
2. 使用实例
// 假设有两个异步函数 asyncFetchData1 和 asyncFetchData2,它们分别返回Promise对象
// 异步函数 asyncFetchData1 ,模拟请求数据1
function asyncFetchData1 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('fetchData1');
}, 1000);
});
}
// 异步函数 asyncFetchData2,模拟请求数据2
function asyncFetchData2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('fetchData2');
}, 1500);
});
}
// 使用 Promise.all 同时执行两个异步函数
Promise.all([asyncFetchData1(), asyncFetchData2()])
.then((results) => {
// 当所有Promise都成功完成时,results是一个包含所有结果的数组
console.log(results); // 输出: ['fetchData1', 'fetchData2']
})
.catch((error) => {
// 如果有任何一个Promise失败,这个catch会捕获到错误
console.error('An error occurred:', error);
});
// 注意:Promise.all 的结果数组中的元素顺序与传入的Promise数组中的顺序一致
三. Promise.race方法
1. 方法详细
Promise.race也是一种用于处理多个 Promise实例的方法,与Promise.all 不同的是,Promise.race 会对比所有的 Promise对象,只要有一个 Promise 对象的状态发生改变,无论是 fulfilled 还是 rejected,Promise.race就返回同样的状态。
2. 使用实例
// 假设有两个异步函数 fetchDataFast 和 fetchDataSlow,它们分别返回 Promise 对象
// 异步函数 fetchDataFast,模拟一个快速完成的 API 请求
function fetchDataFast() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('fastData');
}, 500); // 假设这个请求很快,只需要 500 毫秒
});
}
// 异步函数 fetchDataSlow,模拟一个慢速完成的 API 请求
function fetchDataSlow() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('slowData');
}, 2000); // 假设这个请求很慢,需要 2000 毫秒
});
}
// 使用 Promise.race 同时执行两个异步函数,但只关心第一个完成的结果(无论成功和失败)
Promise.race([fetchDataFast(), fetchDataSlow()])
.then((data) => {
// 这个 .then 会在第一个 Promise 完成时触发
console.log('First data received:', data);
// 输出接收到的第一个数据: fastData
})
.catch((error) => {
// 如果有任何一个 Promise 拒绝,这个 .catch 会捕获到错误
console.error('An error occurred:', error);
});
// 由于 fetchDataFast 比 fetchDataSlow 先完成,因此最终只会输出 fast API 的数据