前言
在JavaScript中处理异步操作总是让人十分头疼,传统的回调函数虽然可以解决问题,但随着代码复杂度的增加,很容易陷入“回调地狱”。为了解决这一难题,ES6引入了Promise,一种更为优雅和可管理的异步编程模式。
回调地狱?
说这么恐怖,那么它到底是什么呢?
举个例子:
当我们使用传统的回调函数来处理吃饭这个流程,我们肯定不能边吃饭边洗碗,所以这些是异步操作,代码就会是这样:
function cook(callback) {
setTimeout(() => {
console.log('做饭');
callback() // 回调函数的调用
}, 2000)
}
function eat(callback) {
setTimeout(() => {
console.log('吃饭');
callback() // 回调函数的调用
}, 1000)
}
function wash() {
setTimeout(() => {
console.log('洗碗');
}, 1000);
}
cook(() => eat(() => wash())); // 箭头函数
// 输出:2秒-> 做饭 ->1秒-> 吃饭 ->1秒-> 洗碗
在这个例子中,cook、eat 和 wash 函数都是异步的,然后在最后一行嵌套成一团,看着都让人头晕,代码可读性较差。这种回调函数的层层嵌套,就是我们所称的“回调地狱”。
超人Promise出现
此刻,超人Promise带你脱离“回调地狱”的苦海。
Promise简述:
它是JavaScript中用于处理异步操作的一种机制,提供了一种更加清晰和结构化的方式来处理异步任务。
举个例子:
为了带大家更好地理解Promise,直观地感受它带来的便利,我将通过用Promise重写上面的流程:
function cook() { //pending resloved rejected
return new Promise((resolve,reject) => { // {status: pending}
setTimeout(() => {
console.log('做饭');
resolve()
}, 2000)
})
}
function eat() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log('吃饭');
resolve()
}, 1000)
})
}
function wash() {
setTimeout(() => {
console.log('洗碗');
}, 500);
}
cook()
.then(() => {
eat()
.then(() => {
wash()
})
})
// 输出:2秒-> 做饭 ->1秒-> 吃饭 ->1秒-> 洗碗
可见,最后的执行代码可读性便增加了许多,then译为中文就是然后,甚至小白都能看懂:cook完然后eat,eat完然后wash。所以这就是为什么封面要用拉勾,就是我向你承诺我会在你后面执行的。
详解Promise
看完上面的代码,你也许会产生疑问了,执行函数看懂了,但在Promise的操作中为什么要传一个名叫resolve的参数然后执行呢?这就得聊一聊Promise的状态了,也是Promise操作中的重点。
Promise的状态
Promise有三种状态:
- pending(待定):初始状态。
- resolved(已成功):也叫fulfilled,表示异步操作成功完成,此时可以获取到操作的结果。
- rejected(已失败):表示异步操作失败,可以获取到失败的原因,通常返回一个错误对象。
想必你就知道刚刚执行resolve的用途了,就是将Promise的状态从pending变成resolved。后面的reject同理,它会将Promise的状态从pending变成rejected,而这里不需要就没有进行调用。要记住的一点是:一旦Promise进入了resolved或者rejected状态后,它就会保持在该状态,不会再改变。
Promise的使用
Promise提供了三种方法:
- .then():接收两个参数,第一个参数是Promise成功时的回调函数,第二个参数(可选)是Promise失败时的回调函数。如果只提供一个参数那么就默认是成功时的回调函数。
- .catch():用于捕获并处理Promise链中任何一个
.then()方法抛出的错误或者reject值 - .finally():不管Promise的结果是成功还是失败,都会执行。
举个例子:
myPromise
.then(result => {
console.log(result); // 输出:异步操作成功
})
.catch(error => {
console.error(error); // 如果异步操作失败,这里会捕获错误
})
.finally(() => {
console.log('无论成功还是失败,我都会执行');
});
fetch
fetch中.then的原理便是使用Promise来处理异步请求的:
fetch(api_url) // 向网页发出请求并获取数据,异步操作
.then(res => res.json()) // 将获取的值变为json格式,也属于异步操作
.then(data =>{
console.log(data);})
.catch(error => {
console.error('Fetch error:', error);
});
通过这最后一个例子,大家应该就充分理解了Promise这个机制。
结语
通过对Promise机制的深入,想必大家对简单的异步处理就更加游刃有余了。它的引入极大地改善了异步编程的复杂性,使代码更好理解和维护。