Promise对象详解(涉及回调地狱的解决、async&await的使用)


之前发现自己对async&await的理解没有那么深,所以翻出笔记又看了一遍!

一、Promise对象

2.1、Promise简介

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

功能:避免了回调地狱,把异步代码改成调用起来像同步代码。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

一个 Promise 对象 有以下几种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

Promise对象有以下两个特点:

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

小结:

  1. Promise是一个构造函数,new出来实例对象可以帮我们解决异步操作的一些问题
  2. 当我们遇到异步操作的时候,都可以使用Promise来加工,便于后期的代码书写

2.2、Promise产生背景

我们如果在进行ajax请求的时候,一个效果需要有多个请求按照一定的顺序完成,如果不使用Promise实现,做起来就容易形成回调地狱

如:

$.ajax({
    url:'url1',
    success(res){
        if(res.code == 200){
            $.ajax({
                url:'url2',
                success(res){
                    if(res.code === 200){
                        $.ajax({
                            url:'url3',
                            success(res){
                                if(res.code === 200){
                                    // TODO
                                }
                            }
                        })
                    }
                }
            })
        }
    }
})

这样的代码是非常不好的,将来想要维护的时候,难度非常高,所以我们不推荐这样的写法。

小结:Promise的出现是用来解决异步回调的多层嵌套问题的(地狱回调)

2.3、Promise的基本使用

Promise的执行流程:

Promise的基本语法:

// 默认pending: 初始状态
var p=new Promise(function (resolve,reject) {
    if("操作成功"){
        resolve();//pending-->fulfilled  异步操作成功的回调函数
    }else{
        reject(); //pending-->reject     异步操作失败的回调函数
    }
})
p.then(data => {//在外面调用then处理成功的逻辑
    console.log("处理成功的逻辑");//fulfilled  
}).catch(err=>{//在外面调用catch处理失败的逻辑
    console.log("失败的逻辑");//reject
})
// then方法会在异步成功后调用,catch方法会在异步失败后调用

例如:

let flag = false;
let p = new Promise((resolve, reject) => {
    if (flag) {
        resolve("做一件大事");
    } else {
        reject("说句对不起");
    }
});
p.then((data) => {
    console.log("我要" + data); //fulfilled
}).catch((err) => {
    console.log("我要" + err); //reject
});

2.4、使用Promise解决回调地狱

Promise的then链式调用的特点:
1、第一个then执行完会执行第二个then
2、then里面的函数的返回值,会被下一个then的形参接收
3、如果返回的是一个promise对象,下一个then的形参接收到的不是这个promise对象,而是这个promise对象内部调用resolve时候的实际参数

2.4.1、如何解决多重请求(回调地狱)
let p1 = new Promise((resolve,reject)=>{
  $.ajax({
    url:'url1',
    success(res){
      resolve(res)
    },
    error(err){
      reject(err)
    }
  })
})
let p2 = new Promise((resolve,reject)=>{
  $.ajax({
    url:'url2',
    success(res){
      resolve(res)
    },
    error(err){
      reject(err)
    }
  })
})
let p3 = new Promise((resolve,reject)=>{
  $.ajax({
    url:'url3',
    success(res){
      resolve(res)
    },
    error(err){
      reject(err)
    }
  })
})

p1.then(res1=>{
  console.log('第一个请求完成')
  return p2;
}).then(res2=>{
  console.log('第二个请求完成')
  return p3
}).then(res3=>{
  console.log('第三个请求完成')
})

这样我们就使用了Promise解决了回调函数里面嵌套回调函数的问题。

小结: 我们可以通过多个promise调用then方法来把地狱回调转化为链式编程,便于后期的维护

2.4.2、简化多重请求的promise写法
function PromiseAjax(url){
  return new Promise((resolve,reject)=>{
    $.ajax({
      url,
      success(res){
        resolve(res)
      },
      error(err){
        reject(err)
      }
    })
  })
}

let p1 = PromiseAjax('url1')
let p2 = PromiseAjax('url2')
let p2 = PromiseAjax('url2')

// TODO ...

2.5、Promise的方法使用

all方法:

  1. 只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。
  2. 只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject("失败");
    }, 3000);
});
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功2");
    }, 2000);
});
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功3");
    }, 1000);
});

// 全部成功返回成功,有一个失败返回失败
let p = Promise.all([p1, p2, p3]).then((res) => console.log(res)).catch(err=>console.log(err));

race方法:
只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

let p = Promise.race([p1, p2, p3])
.then((res) => {
    console.log(res);
})
.catch((err) => {
    console.log("网络状态不佳");
    console.log(err);
});

2.6、异步代码同步化

async函数和await关键字一般成对出现,当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功1");
    }, 3000);
});
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功2");
    }, 2000);
});
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功3");
    }, 1000);
});
//需求,让p1,p2,p3顺序执行
        //除了Promise的回调,我们还可以用async和await
        //async放在函数function前面,表示异步函数
        //await只能写在async函数内部,async执行期间一旦遇到await,会等后面的Promise(异步)执行完毕再执行后面的代码(同步),实现让异步函数在同步函数之前执行
async function getVal(){
    await p1.then(res=>console.log(res))
    //打印res
    await p2.then(res=>console.log(res))
    await p3.then(res=>console.log(res))
}
getVal()

因此,这里的输出是:成功1、成功2、成功3。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

TeresaPeng_zju

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

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

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

打赏作者

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

抵扣说明:

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

余额充值