Promise,async、await的理解与使用

Promise出现之前的异步编程

首先 什么是同步,什么是异步?
  • 同步: 代码从上往下执行 遇见没有延迟的操作 就会一直等 等到完成 才会继续走
  • 异步: 代码从上往下执行 遇见有延迟的操作(定时器,ajax,事件处理,读取文件等) 就执行后面的代码了 ,延迟的代码后面执行
那么,现在提一个要求,使用ajax发出请求获取数据,将得到的数据进行ajax请求,再将第二次获取到的数据进行网络请求…一直这样下去的话,就会形成以下情况:
$.ajax({
            url:"./php/ok.php",
            success:function(res){
              console.log('ajax结果111',res)
                  $.ajax({
                    url:"./php/ok.php",
                    success:function(res){
                      console.log('ajax结果2222',res)
                      $.ajax({
                        url:"./php/ok.php",
                        success:function(res){
                          console.log('ajax结果2222',res)
                          $.ajax({
                              url:"./php/ok.php",
                              success:function(res){
                                console.log('ajax结果2222',res)
                              }
                            })
                        }
                      })
                    }
                  })
            }
          })

一直嵌套下去的ajax请求,最后会形成回调地狱,直到promise的出现,才解决了这个恶心的嵌套。

Promise

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

在一个页面中进行一个操作时,需要进行网络请求,如果这个网络请求是同步的,又因为网络请求需要时间,js代码就会停留在那一部分,就会使得这个页面进入阻塞状态,一直等到网络请求完之前都不能跟页面互动。
一般会给网络请求开启一个异步任务,让页面其他部分正常执行,网络请求完了以后会给一个回调函数,就可以从回调函数里得到网络请求得到的数据(或者请求失败的信息),给后面的js代码使用。

Promise的基本使用

Promise 使用时会传入一个函数作为参数,而这个函数要求传两个参数resolve和reject(resolve和reject也是函数),将需要异步操作的代码放入这个参数函数中,将异步请求得出的数据作为参数传入resolve函数中,在Promise后面使用.then(),其中参数为data,在then函数中单独执行异步请求的数据;Promise的另一个参数reject则是请求异步数据失败时调用,对应的函数.catch();再或者可以将then函数传入两个函数参数,第一个是成功的,第二个是失败的

 	//使用setTimeout()来模拟网络请求
 	//Hello作为参数,参数名为data,传入then函数中。 
    //成功时调用resolve,失败时调用reject
    new Promise((resolve,reject)=>{
      setTimeout(()=>{
        resolve('Hell0')
        reject('error message')
      },1000)
    }).then(data =>{
      console.log(data);
    }).catch(error =>{
      console.log(error);
    })
    // 1s后输出:Hello

回调地狱的解决方法——Promise的链式调用

注:以下都用setTimeout() 来模拟网路请求
下面这段代码是模拟第一次网络请求得到数据h=100,再用h进行第二次网络请求,第二次网络请求会将h*10,然后输出这个结果,且每次请求都耗时1s,也就是在2s后输出1000

  new Promise((resolve,reject) => {
    setTimeout(() => {
      let h = 100
      resolve(h)
      reject('error')
    },1000)
  }).then((result) => {
    console.log('=======after 1s======')
    return new Promise((resolve,reject) => {
      setTimeout(() => {
      let h2 = result * 10
      resolve(h2)
    },1000)
    })
  }).then((result) => {
    console.log('=======after 2s======')
    let h3 = result
    console.log(h3);
  })

咋一看这个链式调用很复杂,拆开来看就简单多了

 new Promise((resolve,reject) => {
    setTimeout(() => {
      let h = 100
      resolve(h)
      reject('error')
    },1000)
  }).then((result) => {
    console.log('=======after 1s======')
    console.log(result)
    })

首先,将return new Promise()后面的内容删去,就是最简单的Promise使用,将网络请求成功的数据h在then()得到

then((result) => {
	console.log('=======after 1s======')
    return new Promise((resolve,reject) => {
      setTimeout(() => {
      let h2 = result * 10
      resolve(h2)
    },1000)
    })
  })             //这一部分就是一个Promise()

在then()函数中return new Promise(),意思是,then()的调用就是在调用这个Promise,而在这个Promise中将h数据(也就是result)*10,的结果作为新的网络请求得到的数据。

.then((result) => {
    console.log('=======after 1s======')
    return new Promise((resolve,reject) => {
      setTimeout(() => {
      let h2 = result * 10
      resolve(h2)
    },1000)
    })
  }).then((result) => {
    console.log('=======after 2s======')
    let h3 = result
    console.log(h3);
  })

然后将这一个then(),也就是新的Promise使用then(),将数据取出,输出
在这里插入图片描述

Promise.all

多个网络请求同时发出请求,并要求同时得到时使用。

使用规则:Promise.all 参数是数组,数组元素是一个Promise函数 ,后面的then函数的参数就是一个数组,其中的元素就是每一个Promise返回的结果

// Promise.all 参数是数组,数组元素是一个Promise函数 ,后面的then函数的参数就是一个数组,其中的元素就是每一个Promise返回的结果
    // 用于解决需要得到多个网络请求而请求时间有差异的情况,Promise.all能将多个网络请求的数据存放在一个数组里
    /// 必须数组里面所有的promise执行完毕才成功。
    Promise.all([
      new Promise((resolve,rejevt) => {
        setTimeout(() => {
          resolve({name:'h',age:21})
        },2000)
      }),
      new Promise((resolve,reject) => {
        setTimeout(() => {
          resolve({name:'ass',age:18})
          reject('ass failed')
        },1000)
        
      })
    ]).then(results => {
      console.log(results[0]);
      console.log(results[1]);
    })

在这里插入图片描述
可以看出,即使后定时2s后的结果放在前面,由于所有网络请求结果是放在一个数组中,并且要在所有数据成功得到后才进行统一处理。所以输出顺序是如上图所示。

async/await

async:

就是Generator函数的语法糖,它建立在Promises上,并且与所有现有的基于Promise的API兼容。

  1. 使用async声明一个异步函数 async function name(){}
  2. 自动将常规函数转化为Promise,返回值也是一个Promise对象
  3. 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数
await

暂停异步的功能执行。

  1. 放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果
  2. 只能与Promise一起使用,不适用于回调
  3. 只能在async函数内部使用。
示例

首先封装一个返回Promise的网络请求函数

function axios(){
              let p1=new Promise(function(resolve,reject) {
                  $.ajax({
                      url:"./php/ok.php",
                      success:function(res){
                        // console.log('ajax结果',res)
                        // console.log(2)
                        // 成功 调用resolve
                        resolve(res)
                      }
                  })
              })
              return p1
              // axios返回一个 promise
          }
          // axios().then(function(res){
          //   console.log('结果',res)
          // })
          // 点击 发送ajax
          // async  await 最简单的使用 就是 可以省略掉then 简单快捷
          //  代码看起来清晰
          document.getElementById("btn").onclick= async ()=>{
            // axios().then(function(res){
            //   console.log('结果',res)
            // })
            let res=await axios();// 这里会等待成功 才执行下面

            let res=await axios();// 这里会等待成功 才执行下面
            console.log('结果',res)
          }
async和await 相比于Promise的优势
  • 代码读起来更加同步,Promise虽然摆脱了回调地狱,但是then的链式调用也会带来额外的阅读负担
  • Promise传递中间值非常麻烦,而async/await几乎是同步的写法,非常优雅
  • 错误处理友好,async/await可以使用成熟的try/catch,Promise的错误捕获非常冗余
  • 调试友好,Promise的调试很差,由于没有代码块,你不能在一个返回表达式的箭头函数中设置断点,如果你在一个.then代码块中使用调试器的步进功能,调试器并不会进入后续的.then代码块,因为调试器只能跟踪同步代码的每一步
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

webhyx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值