当前位置: 首页 > article >正文

生成器的应用 async与await实现

生成器配合使用函数

  • yield 将暂停执行代码,同时把函数返回值传递出去
function s(){console.log('ss');
}
function * f(){/*当 next() 调用时从头开始执行直到yield 开始检查后面的表达式现在是一个函数,那么首先执行函数当函数执行完毕,有返回值下面相当于 yield undefined*/yield s();
}//生成器对象
let g = f();    
//开始执行
console.log(g.next());//{value: undefined, done: false}

生成器配合使用Promise

  • 第一步
  • yield 可以把返回值传递出去,由next()来接受

function do_it(arg){return new Promise((r , j ) =>{setTimeout(() => {r(arg);}, 1000);});
}function * f(){//yield new Promise(...)yield do_it('第一步');
}let g = f();
// res :{value: Promise, done: false}
// res.value 是 yield 传回来的Promise
let res = g.next();
res.value.then(res=>{//第一步console.log(res);
});
  • 第二步
  • next(参数) 可以把参数传递给yield,让yield恢复执行
function do_it(arg){return new Promise((r , j ) =>{setTimeout(() => {r(arg);}, 1000);});
}function * f(){/*yield Promise 并暂停流程*/let res = yield do_it('第一步');//第一次: 第一步console.log('第一次:',res);// yield 第二个 Promise, 同时暂停执行res = yield do_it(res + ' 第二步');}let g = f();
// next 获得 yield 的第一个Promise
let res = g.next();
res.value.then(res=>{/*等第一个Promise执行完后next将第一个Promise的结果传递进去并获得第二个Promise*/let r = g.next(res);   // 第二个Promiser.value.then(res=>{//第一步 第二步console.log(res);});
});
  • 第三步,改良上面的代码
  • 上面代码中都需要自己手写then,再调用next()来执行,其代码结构是一致的
  • 利用递归自动完成

function do_it(arg){return new Promise((r , j ) =>{setTimeout(() => {r(arg);}, 1000);});
}function * f(){let res = yield do_it('第一步');console.log(res);   //第一步res = yield do_it(res + ' 第二步');console.log(res);   //第一步 第二步res = yield do_it(res + ' 第三步');console.log(res);   //第一步 第二步 第三步
}//使用递归来自动化完成
function auto_run(g){function run(arg){let result = g.next(arg);if(result.done)return;result.value.then(res=>{run(res);});}run();
}auto_run(f());

进化到async await

  • 使用async await来简化上面操作
  • 可先看后面的async await的使用

function do_it(arg){return new Promise((r , j ) =>{setTimeout(() => {r(arg);}, 1000);});
}// 异步迭代器 async function *
async function* f(){let res = await do_it('第一步');console.log(res);res = await do_it(res + ' 第二步');console.log(res);res = await do_it(res + ' 第三步');console.log(res);
}(async ()=>{let g = f();let r = await g.next(); //一直迭代到{done:true}时console.log('awwait:',r);
})();

async

  • async 返回一个Promise
async function f(){//return Promise.resolve(123);return 123;
}
let pr = f();
pr.then(res=>{console.log(res);   //123
});
  • 如果函数内部有异常则返回一个Promise.reject();
async function f(){throw new Error('error');
}
let pr = f();
//增加一个 rejected 回调
pr.then(null,res=>{console.log(res);   //error
});

async声明的函数

  • 以下两者等价
async function f(){return 123;
}function ff(){return new Promise((resolve, reject )=>{try{resolve(123);}catch(e){reject(e);}});
}

await

  • await后跟一个表达式,需要在async声明的函数中使用
  • yield的增强版, await将先执行表达式,再暂停流程
  • yield需要手动调用next()执行下一步, await全自动
  • await将创建一个Promise : 使用Promise.resolve()
  • 简单理解就是使用then
async function f(){// await Promise.resolve(3);let res = await 3;console.log(res);  //3
}
f();
  • await 做了什么
async function f(){let result = await 3;
}//相当于
async function f(){Promise.resolve(3).then(res=>{let result = res;});
}
  • 如果await 后面的表达式是一个Promise
//用于返回一个Promise
function test(){return new Promise((resolve , reject)=>{resolve(1);});
}async function f(){let result = await test();
}
  • await相当于
function ff(){//执行此函数,返回一个Promiselet ret = test(); /*await创建一个Promise使用resolve把test()返回值传入*/let await_new_promise = new Promise((resolve,reject)=>{/*resolve的调用时机在: ret 中的 resolve/reject 调用后let res = ret.resolve(1);resolve(res);*/resolve(ret);});// 使用then添加注册函数来获取值await_new_promise.then(res=>{// 相当于 let result = await test();let result = res;console.log(res);   //1});
}

await的yield特性体现在哪里

  • 把上面的代码稍作修改
  • 把await的代码放入一个生成器中,加入yield
  • 外部代码就能使用 .next() 来控制流程
function * gen(){//先调用test(),返回的是一个Promiselet ret = test();//创建一个Promiselet await_new_promise = new Promise((await_resolve, await_reject)=>{//使用Promise.resolve来处理结果await_resolve(ret);});// 传递一个Promiseyield await_new_promise;
}

async await 整体实现

  • 根据上面所知 async 声明的函数将返回一个Promise
  • await将创建一个Promise,并使用then来获取值
  • await是增强版的yield,可暂停流程,也就是使用生成器来控制流程
  • 有如下代码
function test(){return new Promise((resolve , reject)=>{resolve(1);});
}async function f(){let result = await test();
}
  • 异步函数 f 的完整实现
function ff(){// async 声明的函数将返回一个Promisereturn new Promise((r , j)=>{//await 做的事function * gen(){let ret = test();let await_new_promise = new Promise((await_resolve, await_reject)=>{await_resolve(ret);});yield await_new_promise;}// 外部控制流程try {// 第一个 await let g = gen();//next返回一个对象{done:true/false,value:yield后跟的值}let obj = g.next();//获取Promiselet first_await = obj.value;//最终结果let result = undefined;//then中添加fulfilled对应回调来获取结果first_await.then(res=>{result = res;console.log(res); // 1});r(result);} catch (error) {j(error);}
});
}
ff();

与生成器代码比较


function do_it(arg){return new Promise((r , j ) =>{setTimeout(() => {r(arg);}, 1000);});
}// 生成器
function * f(){let res = yield do_it('第一步');console.log(res);   //第一步res = yield do_it(res + ' 第二步');console.log(res);   //第一步 第二步res = yield do_it(res + ' 第三步');console.log(res);   //第一步 第二步 第三步
}
/*生成器需要自己手动调用或者写递归函数来自动调用let g = f();let res = g.next();res.value.then(res=>{g.next(res);....g.next()...});
*///------------------------------------------------/*使用async await全自动
*/
async function ff(){let res = await do_it(1);res = await do_it(res+1);res = await do_it(res+1);console.log('res:',res); // 3
}
ff();

相关文章:

生成器的应用 async与await实现

生成器配合使用函数 yield 将暂停执行代码,同时把函数返回值传递出去 function s(){console.log(ss); } function * f(){/*当 next() 调用时从头开始执行直到yield 开始检查后面的表达式现在是一个函数,那么首先执行函数当函数执行完毕,有返回值下面相当于 yield undefined*/…...

Apache Shiro 统一化实现多端登录(PC端移动端)

Apache Shiro 是一个强大且易用的Java安全框架,提供了身份验证、授权、密码学和会话管理等功能。它被广泛用于保护各种类型的应用程序,包括Web应用、桌面应用、RESTful服务、移动端应用和大型企业级应用。 需求背景 在当今数字化浪潮的推动下&#xff…...

NAT—地址转换(实战篇)

一、实验拓扑: 二、实验需求: 1.实现内网主机访问外网 2.实现外网客户端能够访问内网服务器 三、实验思路 1.配置NAT地址池实现内网地址转换成公网地址,实现内网主机能够访问外网。 2.配置NAT Sever实现公网地址映射内网服务器地址&…...

用HTML和CSS生成炫光动画卡片

这个效果结合了渐变、旋转和悬浮效果的炫酷动画示例&#xff0c;使用HTML和CSS实现。 一、效果 二、实现 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport&quo…...

Vue 3 + Composition API + Vite + Pinia + Element Plus 构建项目的完整指南

以下是使用 Vue 3 + Composition API + Vite + Pinia + Element Plus 构建项目的完整指南,包含 TypeScript 支持配置: 1. 创建项目 使用 Vite 初始化项目 npm create vite@latest my-vue-app -- --template vue-ts如果不需要 TypeScript,使用 --template vue 进入项目目录…...

FPGA_YOLO(三)

上一篇讲的是完全映射&#xff0c;也就是block中的所包含的所有的卷积以及归一&#xff0c;池化卷积 举例总共6个等都在pl侧进行处理&#xff08;写一个top 顶层 里面conv 1 bn1 relu1 pool1 conv1*1 conv 2 bn2 relu2 pool2 conv1*1 ....总共6个 &#xff09;&#xff0c;…...

使用 SQL CTE(公共表表达式)优化数据查询的实践

目录 一、背景 二、什么是 CTE&#xff1f; 三、CTE 的基本结构 四、示例分析 五、CTE 的作用 六、优势分析 一、背景 在数据分析和数据库管理中&#xff0c;SQL 查询的效率和可读性是至关重要的。随着数据量的不断增加&#xff0c;复杂的查询变得越来越难以管理和理解。…...

旅游CMS选型:WordPress、Joomla与Drupal对比

内容概要 在旅游行业数字化转型进程中&#xff0c;内容管理系统&#xff08;CMS&#xff09;的选择直接影响网站运营效率与用户体验。WordPress、Joomla和Drupal作为全球主流的开源CMS平台&#xff0c;其功能特性与行业适配性存在显著差异。本文将从旅游企业核心需求出发&…...

全面适配iOS 18.4!通付盾加固产品全面升级,护航App安全上架

引言&#xff1a; 苹果官方新规落地&#xff01; 自2025年4月24日起&#xff0c;所有提交至App Store Connect的应用必须使用Xcode 16或更高版本构建&#xff0c;否则将面临审核驳回风险&#xff01;Beta版iOS 18.4、iPadOS 18.4现已推出&#xff0c;通付盾iOS加固产品率先完成…...

bash 和 pip 是两种完全不同用途的命令,分别用于[系统终端操作]和[Python 包管理]

bash 和 pip 是两种完全不同用途的命令&#xff0c;分别用于 系统终端操作 和 Python 包管理。以下是它们的核心区别、用法及常见场景对比&#xff1a; 1. 本质区别 特性bashpip类型Shell 命令解释器&#xff08;一种脚本语言&#xff09;Python 包管理工具作用执行系统命令、…...

SQL 通用表表达式(CTE )

目录 概念&#xff1a;CTE&#xff1a; Common table Expression CTE 语法 CTE Demo 概念&#xff1a;CTE&#xff1a; Common table Expression 通用表表达式&#xff08;CTE&#xff09;是SQL中用于简化复杂查询的工具&#xff0c;第一次上线于SQL Server 2005。 CTE提供…...

一台电脑最多能接几个硬盘?

在使用电脑时&#xff0c;硬盘空间不够是许多用户都会遇到的问题。无论是摄影师、剪辑师等需要大量存储空间的专业人士&#xff0c;还是游戏玩家、数据备份爱好者&#xff0c;都可能希望通过增加硬盘来扩展存储容量。然而&#xff0c;一台电脑究竟最多能接多少个硬盘&#xff1…...

MATLAB中iscell函数用法

目录 语法 说明 示例 确定数组是否为元胞数组 iscell函数的功能是确定输入是否为元胞数组。 语法 tf iscell(A) 说明 如果 A 是元胞数组&#xff0c;则 tf iscell(A) 返回 1 (true)。否则&#xff0c;将返回 0 (false)。 示例 确定数组是否为元胞数组 创建一个元胞数…...

【玩转全栈】---- Django 基于 Websocket 实现群聊(解决channel连接不了)

学习视频&#xff1a; 14-11 群聊&#xff08;一&#xff09;_哔哩哔哩_bilibili 目录 Websocket 连接不了&#xff1f; 收发数据 断开连接 完整代码 聊天室的实现 聊天室一 聊天室二 settings 配置 consumer 配置 多聊天室 Websocket 连接不了&#xff1f; 基于这篇博客&…...

如何快速解决django报错:cx_Oracle.DatabaseError: ORA-00942: table or view does not exist

我们在使用django连接oracle进行编程时&#xff0c;使用model进行表映射对接oracle数据时&#xff0c;默认表名组成结构为&#xff1a;应用名_类名&#xff08;如&#xff1a;OracleModel_test&#xff09;&#xff0c;故即使我们库中存在表test&#xff0c;运行查询时候&#…...

Selenium之简介

Selenium简介 首先&#xff0c;让我们看看官网是怎么定义的 Selenium是一个支持web浏览器自动化的一系列工具和库的综合项目&#xff0c;提供了扩展来模拟用户和浏览器的交互&#xff0c;用于扩展浏览器分配的分发服务器&#xff1b;用于W3C WebDriver规范的基础架构 其实&a…...

pip 安装某个包之后,Jupyter Lab仍旧显示包冲突;例如:Numba needs NumPy 2.1 or less. Got NumPy 2.2.

异常提示 Numba needs NumPy 2.1 or less. Got NumPy 2.2. --------------------------------------------------------------------------- ImportError Traceback (most recent call last) Cell In[8], line 53 import pywt4 import matplot…...

本地安装git

下载git 通过官网 下载 &#xff1a;Git - Downloading Package 若此页面无法直达&#xff0c;请删掉download/win尝试 2.双击运行安装 选择安装目录&#xff1a; 选择配置&#xff0c;默认不动 git安装目录名 默认即可 Git 的默认编辑器&#xff0c;建议使用默认的 Vim 编辑器…...

小程序内表格合并功能实现—行合并

功能介绍&#xff1a;支付宝小程序手写表格实现行内合并&#xff0c;依据动态数据自动计算每次需求合并的值&#xff0c;本次记录行内合并&#xff0c;如果列内合并&#xff0c;同理即可实现 前端技术&#xff1a;grid布局 display&#xff1a;grid 先看实现效果: axml&…...

SSE协议介绍和python实现

概述&#xff1a; SSE&#xff08;Server-Sent Events&#xff09;协议是一种允许服务器向客户端实时推送更新的技术&#xff0c;基于HTTP协议&#xff0c;常用于实时数据推送特点&#xff1a; 单向通信&#xff1a;服务器向客户端推送数据&#xff0c;客户端无法发送数据。基…...

甘肃旅游服务平台+论文源码视频演示

4 系统设计 4.1系统概要设计 甘肃旅游服务平台并没有使用C/S结构&#xff0c;而是基于网络浏览器的方式去访问服务器&#xff0c;进而获取需要的数据信息&#xff0c;这种依靠浏览器进行数据访问的模式就是现在用得比较广泛的适用于广域网并且没有网速限制要求的小程序结构&am…...

Spring Boot 3虚拟线程的使用

在Spring Boot非Web应用中&#xff0c;使用虚拟线程时程序提前终止的问题及解决方案&#xff0c;可以通过以下步骤深入理解和验证&#xff1a; 问题根源分析 JVM退出机制 Java中&#xff0c;当所有非守护线程结束时&#xff0c;JVM会立即退出。即使存在正在运行的守护线程&…...

3、pytest实现参数化

在 pytest 中&#xff0c;参数化&#xff08;parametrization&#xff09;是一种强大的功能&#xff0c;可以让你用不同的输入数据重复执行同一个测试函数。这种功能非常有用&#xff0c;可以帮助你显著减少重复代码并提高测试覆盖率。 参数化的主要作用是&#xff1a; 测试多…...

【解决】Linux命令报错:Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64

报错命令 yum install zabbix-web-mysql-scl zabbix-apache-conf-scl centos使用scl切换软件版本时提示Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 报错原因 CentOS7的SCL源在2024年6月30日停止维护了。 当scl源里面默认使用了centos官方的地址&#x…...

WebRTC中音视频服务质量QoS之FEC+NACK调用流程

WebRTC中音视频服务质量QoS之FECNACK调用流程 WebRTC中音视频服务质量QoS之FECNACK调用流程 WebRTC中音视频服务质量QoS之FECNACK调用流程前言一、WebRTC中FEC基础原理1. FEC基础操作 异或操作XOR2、 FEC中 行向和纵向 计算3、 WebRTC中 媒体包分组和生成FEC的包数① kFecRateT…...

神经网络知识点整理

目录 ​一、深度学习基础与流程 二、神经网络基础组件 三、卷积神经网络&#xff08;CNN&#xff09;​编辑 四、循环神经网络&#xff08;RNN&#xff09;与LSTM 五、优化技巧与调参 六、应用场景与前沿​编辑 七、总结与展望​编辑 一、深度学习基础与流程 机器学习流…...

远程办公新体验:用触屏手机流畅操作电脑桌面

在数字化浪潮的推动下&#xff0c;远程办公已从“应急选项”转变为职场常态。无论是居家隔离、差旅途中&#xff0c;还是咖啡厅临时办公&#xff0c;高效连接公司电脑的需求从未如此迫切。然而&#xff0c;传统的远程控制软件常因操作复杂、画面卡顿或功能限制而影响效率。如今…...

【面试八股】:常见的锁策略

常见的锁策略 synchronized &#xff08;标准库的锁不够你用了&#xff09;锁策略和 Java 不强相关&#xff0c;其他语言涉及到锁&#xff0c;也有这样的锁策略。 1. 悲观锁&#xff0c;乐观锁&#xff08;描述的加锁时遇到的场景&#xff09; 悲观锁&#xff1a;预测接下来…...

【python】OpenCV—Hand Detection

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、参考6、其它手部检测和手势识别的方案 更多有趣的代码示例&#xff0c;可参考【Programming】 1、功能描述 基于 opencv-python 和 mediapipe 进行手部检测 2、代码实现 导入必要的库函数 import cv2 import media…...

es6的100个问题

基础概念 解释 let、const 和 var 的区别。什么是块级作用域&#xff1f;ES6 如何实现它&#xff1f;箭头函数和普通函数的主要区别是什么&#xff1f;解释模板字符串&#xff08;Template Literals&#xff09;的用途&#xff0c;并举例嵌套变量的写法。解构赋值的语法是什么…...