ES6异步编程解决方案——async、Generator、Promise

34 篇文章 0 订阅
9 篇文章 1 订阅

目录

一、async异步函数

二、Generator 生成器函数

三、Promise


一、async异步函数

async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。

await关键字只在async函数内有效。如果你在async函数体之外使用它,就会抛出语法错误 SyntaxError 。async/await的目的为了简化使用基于promise的API时所需的语法。async/await的行为就好像搭配使用了生成器和promise。async函数一定会返回一个promise对象。如果一个async函数的返回值看起来不是promise,那么它将会被隐式地包装在一个promise中。

简单来说,async是一个函数,是一个异步编程解决方案,内部封装了generator函数,是一个语法糖,内部自带执行器,与await配合使用;异步编程,同步处理。

例子:
使用axios发送一个异步请求:
先引入axios:直接去BootCDN上搜索axios,然后复制script标签放到我们的页面中即可

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>
</head>
<body>
  <script>
    // async和await配合使用
    async function loadAll(){
      // 发送一个get请求
      let res = await axios.get('https://api.muxiaoguo.cn/api/lishijr?api_key=51247282aed5c8dc')
      console.log(res);
    }
    loadAll()
  </script>
</body>
</html>

结果如下,请求成功 

 我们可以使用try、catch和finally来捕获异常:

try中放我们要执行的代码,catch中放请求失败时执行的代码,finally无论请求是否成功都会执行里面的代码。

<script>
    async function loadAll(){
      // 发送一个get请求
      try{
        let res = await axios.get('https://api.muxiaoguo.cn/api/lishijr?api_key=51247282aed5c8dc')
        console.log(res);
      }catch(error){
        // console.log(error);
        throw new Error('请求失败')
      }finally{
        console.log('最终都会执行');
      }
    }
    loadAll()
</script>

结果如下: 

二、Generator 生成器函数

Generator是ES6提供的一种异步编程解决方案,语法不同于普通函数;我们可以简单的把Generator 理解为一个状态机,封装了多个内部状态。执行Generator 函数会返回一个迭代器对象,可以通过调用迭代器的next方法依次遍历Generator函数内部的每一个状态。(一个yield就是一个状态,一个yield就是一个代码节点)

如果不了解迭代器的,可以看这里:https://blog.csdn.net/LQ313131/article/details/126891697

Generator函数有两个特征:
1、function关键字与函数名之间有个星号

function* test(){}

2、函数内部使用yield表达式

Generator提供了yield来对函数结果进行返回,它与return不同,return会阻止后面的代码运行,而yield不会。

例子:

<script>
  function* Generator(){
    // 内部使用yield表达式
    console.log('11111');
    yield '我是第一个状态返回值,我被执行了'//返回值 对这个状态的描述
    console.log('22222');
    yield '我是第二个状态返回值,我被执行了'
    console.log('33333');
    yield '我是第三个状态返回值,我被执行了'
  }
  let res = Generator()//返回一个迭代器对象/Generator对象
  console.log(res.next()); //执行第一个状态
  console.log(res.next()); //执行第二个状态
  console.log(res.next()); //执行第三个状态
</script>

结果如下:

上述代码有三个状态,一个yield就是一个状态,一个yield就是一个代码运行节点,执行一次迭代器的next方法,到第一个yield,再执行一次,到下一个yield。yield后面是每一种状态的描述。通过迭代器对象的next方法控制的代码的向下执行。

代码分段执行,一个yield分一段。上一个yield结束是下个状态的开始,下一个状态的结束再执行下一个yield。yield后面的是返回值。

如果我们想要在第二个状态拿第一个状态的返回值,就需要在第二个状态执行的时候传递参数,直接使用是获取不到的。

例子:

<script>
    function* test() {
      let res = yield '1'; //将状态一的返回值赋值给res变量, 注意:拿到的不是yield后面的状态描述
      // 我们想要在第二个状态使用第一个状态得返回值,直接使用是获取不到得
      console.log(res, '获取res'); //100 '获取res'
      yield '2';
      yield '3';
    }
    let res = test(); //返回值 返回的是一个迭代器对象/generator对象
    res.next(); //发起第一个状态的执行
    res.next(100);// 如果想要在第二个状态拿第一个状态得返回值,就需要在第二个状态执行得时候传递参数
</script>

接下来,我们模拟发起异步请求,拿到第一个状态的返回结果再执行第二个状态,状态之间数据传递通过next。

<script>
    function* test() {
      let res = yield getData();
      console.log(res, '获取响应');
      yield '结束了';
    }
    let res = test(); //返回值 返回的是一个迭代器对象/generator对象
    res.next();
    async function getData() {
      // 发起一个异步请求
      let result = await axios.get('https://api.muxiaoguo.cn/api/lishijr?api_key=51247282aed5c8dc');
      // 应该在第一个状态的异步请求中发起第二段程序/第二个状态的执行 
      // 上一个状态返回值作为下一个状态的入口
      // 第一个状态的方法里面发起第二个状态的执行 
      res.next(result);
    }
</script>

三、Promise

Promise是一种异步编程解决方案,Promise是一个容器,保存着将来才会执行的代码;从语法角度来说Promise是一个对象,可以用来获取异步操作的消息。异步操作,同步解决,避免了层层嵌套的回调函数,可以链式调用降低了操作难度。

创建一个promise对象:

let promise = new Promise((resolve,reject)=>{
  // resolve 代表的是成功的回调函数 
  // reject 代表的是失败的回调函数
});
//打印promise
console.log(promise);

  

Promise构造函数接收一个函数作为参数,也就是回调函数;该回调函数的两个参数分别是resolve和reject。resolve作为成功的回调函数,reject作为失败的回调函数。Promise对象代表一个异步操作有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。最后返回resolved(已定型)结果。

resolve 和 reject 回调函数由谁提供?
在promise原型里有then和catch方法,resolve由then方法提供,reject由catch方法提供。
then方法表示的是成功之后的回调;catch方法表示的是失败之后的回调。

例子:模拟异步请求

<script>
    let promise = new Promise((resolve, reject) => {
      // 模拟异步请求
      if (3 > 2) {
        resolve('success')
      } else {
        reject('error')
      }
    });

    // 实例方法
    promise.then(
    	// 执行的是成功的回调函数
    	(res)=>{
    		console.log(res,'请求成功');
    	}
    ).catch(
    	// 执行的是失败的回调函数
    	(err)=>{
    		console.log(err,'请求失败');
    	}
    ).finally(()=>{
    	console.log('最终执行');
    });
</script>

如果then里面传了两个回调函数,第一个代表成功之后的回调,第二个代表失败之后的回调,分别代表resolve()和reject()

<script>
    let promise = new Promise((resolve, reject) => {
      // 模拟异步请求
      if (3 > 2) {
        resolve('success')
      } else {
        reject('error')
      }
    });

    promise.then(res => {
      console.log(res, '请求成功');
    }, err => {
      console.log(err, '请求失败');
    })
</script>

有时候我们可能有多个请求需要发送,需要创建多个promise对象,这时候可以采用工厂函数进行封装。

例子:对原生ajax进行封装

<script>
		function promise(method, url) {
			return new Promise((resolve, reject) => {
				// 创建XMLHttpRequest的实例对象
				let xhr = new XMLHttpRequest();
				// 打开一个连接
				xhr.open(method, url);
				// 发送请求
				xhr.send();
				// 接收响应
				xhr.onreadystatechange = function () {
					if (xhr.readyState === 4) {
						if (xhr.status === 200) {
							// 代表请求成功 
							resolve(xhr.responseText)
						} else {
							// 代表请求失败
							reject(xhr.responseText)
						}
					}
				}
			})
		}
		let p1 = promise('get', 'https://api.muxiaoguo.cn/api/lishijr?api_key=51247282aed5c8dc');
		let p2 = promise('get', 'https://api.muxiaoguo.cn/api/xiaohua?api_key=fd3270a0a9833e20');
		p1.then(res => {
			console.log(res, '获取响应1');
		});
		p2.then(res => {
			console.log(res, '获取响应2');
		});
</script>

Promise中的静态方法(只能由构造函数本身去调用):

Promise.all([p1,p2])

参数:数组,数组中的元素为Promise实例

返回值:Promise实例,当p1、p2状态都为fulfilled时候,该实例的状态才为fulfilled,此时p1,p2的返回值组成一个数组,传递给该实例的回调函数;只要p1,p2的返回值有一个变为rejected,该实例状态为rejected;

Promise.race([p1,p2])

赛跑返回先请求成功的实例

参数:数组,数组中的元素为Promise实例 返回值:Promise实例,当p1、p2之中有一个实例率先改变状态,该实例的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给该实例的回调函数。

Promise.any([p1,p2])

参数:数组,数组中的元素为Promise实例

返回值:Promise实例,只要p1、p2状态有一个变为fulfilled,该实例的状态为fulfilled;p1,p2状态都变为rejected,该实例状态才为rejected

<script>
    function promise(method, url) {
      return new Promise((resolve, reject) => {
        // 封装ajax
        let xhr = new XMLHttpRequest();
        // 打开一个连接
        xhr.open(method, url);
        // 发送请求
        xhr.send();
        // 接收响应
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            if (xhr.status === 200) {
              // 代表请求成功 
              resolve(xhr.responseText)
            } else {
              // 代表请求失败
              reject(xhr.responseText)
            }
          }
        }
      })
    }
    let p1 = promise('get', 'https://api.muxiaoguo.cn/api/lishijr?api_key=51247282aed5c8dc');
    let p2 = promise('get', 'https://api.muxiaoguo.cn/api/xiaohua?api_key=fd3270a0a9833e20');

    // 实例全部成功返回一个承诺对象
    let res = Promise.all([p1, p2]);
    console.log(res);

    // 任意一个实例状态成功返回成功的实例
    let res1 = Promise.any([p1, p2]);
    console.log(res1);

    // race 赛跑 返回请求先成功的实例对象
    let res2 = Promise.race([p1, p2]);
    console.log(res2);

    // 返回的处理格式 array:[{},{}]
    let res4 = Promise.allSettled([p1, p2]);
    console.log(res4);
    res4.then(res => {
      console.log(res);
    })
</script>

 

all();     实例状态全部成功,返回的承诺对象状态才是成功
any();   实例状态任意一个成功,返回的承诺对象状态就是成功
race();  实例状态返回请求先成功的那一个
allSettled();  返回全部处理实例 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值