从回调地狱到Promise乐园:JavaScript异步编程的进化

前言

 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步!

 🍅 个人主页:南木元元


目录

什么是Promise

Promise的特点

Promise的基本用法

创建Promise对象

then

resolve/reject

catch

常用方法

Promise.all()

Promise.allSettled()

Promise.race() 

Promise.any() 

Promise.finally() 

结语


什么是Promise

Promise是一种异步编程的解决方案,它代表一个尚未完成但预期将来会完成的操作,并可以在这个操作完成或失败时处理相应的结果。Promise 提供了一种更清晰和结构化的方式来编写和管理异步代码,避免了“回调地狱”(callback hell)的出现。

简单来说,Promise就相当于一个容器,里面保存异步操作的结果,解决了回调地狱的问题。

  • 回调地狱

Promise出现之前,JavaScript的异步机制主要通过回调函数来实现,但使用回调函数的方式有一个缺点:多个回调函数嵌套时会造成回调函数地狱,导致代码难以阅读和维护。

callback1(function(result1) {
  callback2(result1, function(result2) {
    callback3(result2, function(result3) {
      callback4(result3, function(result4) {
        // 最终结果处理
        console.log(result4);
      });
    });
  });
});

在上面示例中,每个异步操作的结果都被传递给下一个回调函数,随着异步操作的增加,这种嵌套会变得复杂和难以管理。

而使用 Promise 的方式可以将嵌套的回调函数作为链式调用,从而避免回调地狱。

Promise的特点

Promise实例有三种状态:

  • pending:进行中,是初始状态
  • fulfilled:已成功
  • rejected:已失败

Promise实例有两个过程:

  • pending -> fulfilled 
  • pending -> rejected

当把一件事情交给promise时,它的状态就是pending,任务完成了状态就变成了fulfilled,没有完成失败了就变成了rejected。状态的改变是通过 resolve() 和 reject() 函数来实现的。

Promise的两个特点:

特点1:只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

特点2:实例的状态一经改变,就凝固了,无法再被改变了。

Promise的基本用法

创建Promise对象

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。

const promise = new Promise(function(resolve, reject) {
  // 做一些事情
  if (/* 异步操作成功 */){
    // 当调用 resolve 函数的时候,Promise 的状态就变成 fulfilled
    resolve(value);
  } else {
    // 当调用 reject 函数的时候,Promise 的状态就变成 rejected
    reject(error);
  }
});

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。resolve 将Promise的状态由等待变为成功,将异步操作的结果作为参数传递过去; reject 则将状态由等待转变为失败,将异步操作报出的错误作为参数传递过去。

then

Promise实例创建完成后,可以使用 then方法分别指定成功或失败的回调函数。

promise.then(function(value) {
  // 如果状态是成功,调用成功回调函数
}, function(error) {
  // 如果状态是成功,调用成功回调函数
});

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为fulfilled时调用,第二个回调函数是Promise对象的状态变为rejected时调用(该参数可以省略)。 then方法返回的是一个新的Promise实例,因此可以采用链式写法,即then方法后面再调用另一个then方法。

resolve/reject

一般情况下都会使用 new Promise() 来创建promise对象,但是也可以使用 promise.resolve 和 promise.reject 这两个方法。

Promise.resolve() :返回一个成功的promise对象,并且将该结果传递给对应的then方法。

Promise.resolve(11).then(function(value){
 console.log(value); // 打印出11
});

Promise.reject() :返回一个失败的Promise对象,并将给定失败信息传递给对应处理方法。

Promise.reject(new Error("我错了!"));

就是下面的代码new Promise的简单形式:

new Promise(function(resolve,reject){
   reject(new Error("我错了!"));
});

catch

catch方法相当于then方法的第二个参数,不过catch方法还有一个作用,就是在执行resolve回调函数时,如果出现错误,抛出异常,不会停止运行,而是进入catch方法中。

promise.then((data) => {
    console.log(data);
}).catch((err) => {
    console.log(err);
});

then和catch对状态的影响

then 方法和 catch方法,只要不报错,返回的都是一个fulfilled状态;如果报错,返回rejected。

const p1 = Promise.resolve().then(()=>{
 throw new Error('then error')//then里面报错返回rejected
})

p1.then(()=>{
 console.log(456)
}).catch(err=>{
 console.log(789) //789 p1是rejected会触发后续catch回调
})

const p2 = Promise.reject('my error').catch(()=>{
 console.log('catch error')//catch正常返回fulfilled
})

p2.then(()=>{
 console.log(1)
//catch error 1 p2返回fulfilled 触发then回调
})

常用方法

Promise.all()

可以完成并行任务, 它接收一个数组,数组的每一项都是一个 promise 对象。当所有结果成功时会返回按照请求顺序排列的结果数组,如果有一个失败,就会返回该失败状态的值。

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
 setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
 console.log(values); //[3, 42, "foo"]
});

应用场景:发送多个请求并根据请求顺序获取和使用数据的场景。

Promise.allSettled()

跟 Promise.all 类似, 唯一的不同在于可以拿到每个 Promise 的状态,而不管其是否处理成功。

Promise.race() 

接受的参数是一个 promise 对象数组,会返回最先执行完成的promise对象的结果,不管结果是成功还是失败状态。

let promise1 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       reject(1);
	},2000)
});
let promise2 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(2);
	},1000)
});
let promise3 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(3);
	},3000)
});
Promise.race([promise1,promise2,promise3]).then(res=>{
	console.log(res);
	//结果:2
},rej=>{
    console.log(rej)};
)

应用:当要做一件事,超过多长时间就不做了,可以用这个方法来解决。

Promise.any() 

接受的参数是一个Promise对象数组,只要其中的一个 promise 成功,就返回那个promise的值。 如果所有实例都失败,会以一个包含拒绝原因数组的AggregateError拒绝。

Promise.finally() 

不管 Promise 对象最后状态如何,都会执行 finally 方法指定的回调函数。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。比如服务器使用 Promise 处理请求,然后使用 finally 方法关掉服务器。

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~ 

  • 88
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 69
    评论
评论 69
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南木元元

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值