异步编程之Promise篇

381 阅读4分钟

前言

在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秒-> 洗碗

在这个例子中,cookeatwash 函数都是异步的,然后在最后一行嵌套成一团,看着都让人头晕,代码可读性较差。这种回调函数的层层嵌套,就是我们所称的“回调地狱”。

超人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机制的深入,想必大家对简单的异步处理就更加游刃有余了。它的引入极大地改善了异步编程的复杂性,使代码更好理解和维护。