promise的理解 跟 async / await 语法

Promise是JavaScript中用于解决异步编程问题的工具,它可以避免回调地狱,使代码更加优雅。Promise有三种状态:pending(进行中)、fulfilled(已完成)和rejected(已失败)。async/await是ES7引入的语法,使得异步代码看起来更像同步代码,通过await关键字可以等待Promise完成并获取结果。文章通过实例解释了如何使用Promise的链式调用和async/await进行优雅编程,并讨论了它们的兼容性问题。
摘要由CSDN通过智能技术生成

promise :什么是promise呢?

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

简单理解 Promise是解决回调地狱的方案之一 把回调地狱写的优雅的方案之一

简单举个例子:
Promise 单词
+ 承诺, i promise, i will love you forever
+ 这个承诺有几个状态(三个)
1. 承诺继续 => 两个人在一起过日子
2. 成功 => 最后两个人埋在一个坟里面
3. 失败 => 有一个人埋在别人的坟里
+ 一旦状态确定, 不可变更
=> 继续 -> 成功
=> 继续 -> 失败
=> 不可能由成功转变为失败
+ 对应在 Promise 的语法里面的时候
=> 继续 -> pending -> 正在进行时
=> 成功 -> fulfilled -> 过去完成时
=> 失败 -> rejected -> 过去完成时

(1)
Promise 是做什么的
+ 承诺会帮你做 异步的事情
+ 会在成功的时候给你一个成功的回调
+ 会在失败的时候给你一个失败的回调
+ 我们把异步的事情交给 promise 来做
=> 我们等待结果就好
=> pending 继续, 也就是正在帮你做这个异步的事情
=> fulfilled 成功, 结果
=> rejected 失败, 结果
(2)
Promise 类比在 ajax 请求里面
=> pending 就是正在请求(网络传输过程中)
=> fulfilled 就是请求成功了(网络环境允许请求, 可以连接到服务器拿到结果)
=> rejected 就是请求失败了(突然没有网了, 掉线了, 不会再有结果回来了)
(3)
Promise 的语法
+ 在 es6 里面有一个内置的构造函数叫做 Promise
+ 语法: let p1 = new Promise(function () { 你要做的异步的事情 })
+ promise 对象里面由两个方法
+ 一个叫做 then => 就是 p1 帮你做的异步的事情成功的时候执行的
+ 一个叫做 catch => 就是 p1 帮你做的异步的事情失败的时候执行的


举个例子:
    // 应用一下 promise
    //   先用定时器来模拟
    var p1 = new Promise(function (resolve, reject) {
      // 帮我做一件异步的事情
      var xhr = new XMLHttpRequest()

      xhr.open('请求方法', 'URL路径')

      xhr.onreadystatechange = function () {
        if (xhr.status === 200 && xhr.readyState === 4) {
          resolve(xhr.responseText) // 实参
          // 给的就是后端返回的内容
        }

        if (xhr.status === 404) {
          reject('请求地址不对')
        }
      }

      xhr.send()
    })

    // then 函数
    p1.then(function (res) { // 形参
      console.log('我执行了, 我表示成功')
      // res 接受到的就是 resolve () 里面的实参 => 100
      // res 接收到的就是 后端返回的内容
      console.log(res)
    })

    // catch 函数
    p1.catch(function () {
      console.log('我执行了, 我表示失败')
    })

  • 现在上面这段代码的执行顺序
    1. 遇到了一个 Promise帮我发送一个 ajax 请求
    -> 发现这个是一个异步的 ajax
    -> 就把这个 异步的 ajax 往后放
    2. 遇到了一个 p1.then(function a() {})
    -> 就把这个回调函数帮我们准备好了传递到 promise 里面
    3. 遇到了一个 p1.catch(function b() {})
    -> 就把这个回调函数帮我们准备好了传递到 promise 里面
    到这个时候
    -> 所有的同步代码都执行完毕了
    -> a 和 b 函数只是传递到了 promise 里面, 但是没有调用
    -> 接下来就该异步的 ajax 执行了
    4. 等到 ajax 结束的时候
    -> 根据 ajax 的状态或者说成功还是失败
    -> 来调用之前就准备好的成功的回调或者失败的回调

Promise的链式调用

  • Promise 的链式调用
    + then 是成功的回调
    + 只要 then 里面再次 return 一个 promise 对象
    + 那么就可以在这个 then 后面继续 then

举个例子

    var p1 = new Promise(function (resolve, reject) {
      // 异步的事情先用定时器模拟
      setTimeout(function () {
        resolve() // 成功的回调
      }, 1000)
    })

    // 1s 以后执行这个 then 函数
    p1.then(function () {
      console.log('我是 p1 的 then 函数里面的代码')
      // 准备第二个 promise 对象
      var p2 = new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve() // 调用的第二个 then
        }, 1000)
      })

      // p2 是一个 promise 对象
      // 返回一个 promise 对象
      return p2
    }).then(function () {
      // 我会在 p2 的 resolve() 的时候执行
      console.log('我是 p1 then 后面的第二个 then')
    })

    // 在 p1 的 then 里面 return 了一个新的 promise 对象

优雅编程

  • 优雅的编程
    + 使用 Promise 的方式二次封装 ajax

    需求:
    1. 发送一个请求到 a.php
    -> 能得到一个结果
    -> 是两个数组
    2. 发送第二个请求到 b.php, 需要在第一个请求结束以后发送
    -> 需要携带第一个请求给返回来的两个数字
    -> 能得到一个结果
    -> 包含你带过去的两个数字的和, 和第三个数字
    3. 发送第三个请求到 c.php, 需要在第二个请求结束以后发送
    -> 需要携带第二个请求给返回来的两个数字
    -> 能得到一个结果, 是两个数字的乘积

    function pGetSend(url) {
      // 利用 promise 帮我们做一个 异步的 ajax 请求
      var p1 = new Promise(function (resolve, reject) {
        // 直接发送一个 ajax 请求
        var xhr = new XMLHttpRequest()
        xhr.open('GET', url)
        xhr.onload = function () {
          resolve(xhr.responseText) // 在请求成功的时候调用一下 resolve()
        }
        xhr.send()
      })

      return p1
    }


    pGetSend('./server/a.php')
      .then(function (res) {
        console.log('第一次请求的结果')
        // 是个 json 格式, 我们不方便获取内容
        // 使用 JSON.parse 解析一下
        var result = JSON.parse(res)
        console.log(result)

        // return一个新的 promise 对象
        return pGetSend(`./server/b.php?n1=${result.n1}&n2=${result.n2}`)
      })
      .then(function (res) {
        console.log('第二次请求的结果')
        // console.log(res) // json 格式, 我们要解析一下
        var result = JSON.parse(res)
        console.log(result)

        return pGetSend(`./server/c.php?and=${result.and}&n3=${result.n3}`)
      })
      .then(function (res) {
        console.log('第三次请求的结果')
        console.log(res)
      })

    // a 得到的就是 pGetSend 这个函数里面 return 出来的东西
    //   pGetSend 里面 return 出来的就是 p1
    //   等价于 a = p1
    // var a = pGetSend('./server/a.php')

    // // p1 之所以可以 .then 是因为 p1 是一个 promise 对象
    // //   可以写 p1.then 就可以写 a.then
    // a.then(function (res) {
    //   console.log(res) // 上面 p1 调用 resolve() 的时候传递的响应体
    // })

其中php中代码

  1. a.php:
<?php

  # 准备两个数组返回
  $arr = array( "n1" => 100, "n2" => 200 );

  // 变成 json 格式返回
  echo json_encode($arr);

?>
  1. b.php
<?php

  // 1. 接受前端传递来的参数
  $n1 = $_GET['n1'];
  $n2 = $_GET['n2'];

  // 2. 求一个 和
  $and = $n1 + $n2;

  // 3. 准备一个关联型数组返回
  $arr = array( "and" => $and, "n3" => 5 );
  echo json_encode($arr);


?>

3.c.php:

<?php

  // 1. 接受前端传递来的参数
  $and = $_GET['and'];
  $n3 = $_GET['n3'];

  // 2. 求一个乘积
  $chengji = $and * $n3;

  // 直接返回数字
  echo $chengji;

?>

async / await 语法

  • +es7 的语法
    + 把异步代码写的 看起来像 一个同步代码
    -> 代码只是看着像是同步代码
    -> 本质还是异步代码
    + 前提: Promise
    + async => 异步
    + await => 等待

  • 语法规范
    1. async 关键字必须写在一个函数的前面
    2. await 关键字是一个写在 异步函数 里面的关键字
    -> 你想使用 await 关键字, 那么函数前面必须有 async 关键字
    3. await 关键字后面必须是一个 promise 对象
    + 有了 await 以后
    + 我们就可以把本该在 then 里面接受的结果
    + 在 await 前面定义一个变量来接受

    兼容性问题
    + 我们的 Promsie 和 async/await 语法都是兼容性不好
    -> 一个是 es6 一个是 es7
    -> 语法层面的兼容
    + 语法层面的兼容我们不需要考虑
    -> 因为最后我们有一个工具叫做 babel
    -> 能帮我们做的事情就是 es6 es7 转换成 es5 语法
    + 例子:
    -> let num = 100, IE 低版本不兼容
    -> let { name } = obj, IE 低版本不兼容
    -> hello ${a}, IE 低版本不兼容
    -> 我们的 babel 就能把这种语法变成 es5 的语法

    // pGetSend() 函数执行的时候能返回一个 promise 对象
    function pGetSend(url) {
      // 利用 promise 帮我们做一个 异步的 ajax 请求
      var p1 = new Promise(function (resolve, reject) {
        // 直接发送一个 ajax 请求
        var xhr = new XMLHttpRequest()
        xhr.open('GET', url)
        xhr.onload = function () {
          resolve(xhr.responseText) // 在请求成功的时候调用一下 resolve()
        }
        xhr.send()
      })

      return p1
    }

使用 async / await 语法完成刚才的三个需求

async function fn() {

      // 1. 第一个请求
      var res = await pGetSend('./server/a.php')
      var result = JSON.parse(res)
      console.log('第一次请求的结果')
      console.log(result)

      // 2. 第二个请求
      var res2 = await pGetSend(`./server/b.php?n1=${result.n1}&n2=${result.n2}`)
      var result2 = JSON.parse(res2)
      console.log('第二次请求的结果')
      console.log(result2)

      // 3. 第三个请求
      var res3 = await pGetSend(`./server/c.php?and=${result2.and}&n3=${result2.n3}`)
      console.log('第三次请求的结果')
      console.log(res3)

    }

    fn()

  • 解释 async / await 语法
    a 得到的就是一个 promise 对象
    var a = pGetSend(’./server/a.php’)

    async function fn() {
    这个本该在 then 里面接受的 res 就是后端的响应
    如果你有 await, 就可以直接在 await 前面定义一个变量
    来接受这个本该在 then 里面接受的内容
    pGetSend(’./server/a.php’)
    .then(function (res) {
    console.log(res)
    })

    res 接受的就是 pGetSend 的 then 里面接受的内容
    var res = await pGetSend(’./server/a.php’)

    await 是什么意思
    当 await 后面是一个 promise 对象的时候
    那么就会把代码停止在这里不动了, 等到后面 promise 里面的异步事情做完以后
    把结果给到前面的变量, 在继续向后执行代码
    只生效在当前作用域内部, 也就是这个 async 函数内部
    pGetSend 是一个异步的 ajax 请求
    await 就会等到这个 异步的请求结束, 并且把结果给到前面的 res 变量以后
    在继续向后执行 console.log(res) 这一句代码

    console.log(res)

    }

    调用一下上面的 fn 函数
    fn()

了解更多点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值