必看!总结5种JavaScript异步解决方案
1.回调
回调简单地理解为一个函数作为参数传递给另一个函数,回调是早期最常用的异步解决方案之一。
回调不一定是异步的,也不直接相关。
举个简单的例子:
function f1(cb) {setTimeout(() => {cb && cb();}, 2000);
}f1(() => {console.log("1");
});
如上,我们在函数f1中使用setTimeout模拟一个耗时2s的任务,在耗时任务结束时抛出回调,这样我们就可以调用它,让回调函数在耗时结束时执行函数 f1 中的任务。
这样,我们就把同步操作变成了异步操作。f1不会阻塞程序,相当于先执行程序的主要逻辑,推迟执行耗时操作。
回调的优点和缺点
优点:简单,容易理解。
缺点:代码不优雅,可读性差,不易维护,耦合度高,层层嵌套造成回调地狱。
2.事件监听(发布订阅模式)
发布-订阅模式定义了对象之间一对多的依赖关系,这样当一个对象的状态发生变化时,所有依赖它的对象都会得到通知。
我们都使用过发布-订阅模式,例如,如果我们将事件函数绑定到 DOM 节点。
document.body.addEventListener('click', function () {console.log('click');
})
但这只是发布-订阅模式最简单的使用,在很多场景下我们往往会使用一些自定义事件来满足我们的需求。
有很多方法可以实现发布-订阅模式,所以这里有一个使用类的简单实现。
class Emitter {constructor() {// _listener array, key is the custom event name, value is the execution callback array - as there may be more than onethis._listener = []}// 订阅 监听事件on(type, fn) {// Determine if the event exists in the _listener array.// Exists to push the callback to the value array corresponding to the event name, does not exist to add directlythis._listener[type] ? this._listener[type].push(fn) : (this._listener[type] = [fn])}// Publish Trigger Eventtrigger(type, ...rest) {// Determine if the trigger event existsif (!this._listener[type]) return// Iterate through the array of callbacks executing the event and pass the parametersthis._listener[type].forEach(callback => callback(...rest))}
}
如上所示,我们创建了一个 Emitter 类,并在和触发器上添加了两个原型方法,使用如下。
// Create an emitter instance
const emitter = new Emitter()emitter.on("done", function(arg1, arg2) {console.log(arg1, arg2)
})emitter.on("done", function(arg1, arg2) {console.log(arg2, arg1)
})function fn1() {console.log('I am the main program')setTimeout(() => {emitter.trigger("done", "Asynchronous parameter I", "Asynchronous parameter II")}, 1000)
}fn1()
我们先创建一个emitter实例,然后注册事件,然后触发事件,这样也解决了异步问题。
事件监听的优点和缺点
优点:更符合模块化思想,我们在编写自己的监听器的时候可以做很多优化,从而更好的监听程序的运行。
缺点:整个程序变成了事件驱动,或多或少影响了流程,而且每次使用都要注册事件监听器然后触发,比较麻烦,代码也不是很优雅。
3.Promise
ES6 标准化并引入了 Promise 对象,这是一种异步编程的解决方案。
简单的说,就是用同步的方式写异步代码,可以用来解决回调地狱问题。
Promise对象的状态一旦改变,就不会再改变,只有两种可能的改变。
-
由待定改为已解决。
-
由Pending改为Rejected。
我们使用 setTimeout 来模拟异步操作。
function analogAsync(n) {return new Promise((resolve) => {setTimeout(() => resolve(n + 500), n);});
}function fn1(n) {console.log(`step1 with ${n}`);return analogAsync(n);
}function fn2(n) {console.log(`step2 with ${n}`);return analogAsync(n);
}function fn3(n) {console.log(`step3 with ${n}`);return analogAsync(n);
}
使用 Promise 来实现。
function fn() {let time1 = 0;fn1(time1).then((time2) => fn2(time2)).then((time3) => fn3(time3)).then((res) => {console.log(`result is ${res}`);});
}fn();
Promise 优点和缺点
优点:Promise以同步的方式编写异步代码,避免了回调函数层层嵌套,可读性更强。链式操作,可以在then中继续写Promise对象并return,然后继续调用then进行回调操作。
缺点:Promise对象一旦创建就会立即执行,不能中途取消。如果没有设置回调函数,Promise 会在内部抛出错误,不会向外流。
4.Generator
Generator其实就是一个函数,只不过是一个特殊的函数。Generator 的特别之处在于它可以中途停止。
function *generatorFn() {console.log("a");yield '1';console.log("b");yield '2'; console.log("c");return '3';
}let it = generatorFn();
it.next();
it.next();
it.next();
it.next();
上面的示例是一个具有以下特征的生成器函数。与普通函数不同,Generator 函数在函数之后和函数名称之前有一个 *,该函数有一个内部 yield 字段,函数调用后的返回值使用next方法。
Generator的优点和缺点
优点:优雅的流程控制方法,允许函数被中断地执行。
缺点:Generator函数的执行必须依赖executor,对于只做异步处理还是不太方便。
5.async/await
ES2017标准引入了async函数,使得异步操作更加方便。async是异步的意思,await是async wait的简写,也就是异步等待。async/await 被许多人认为是 js 中异步操作的终极和最优雅的解决方案。
异步在做什么?
async 函数返回一个 Promise 对象。如果直接在 async 函数中返回一个直接量,async 会通过 Promise.resolve() 将直接量包装在一个 Promise 对象中。
await 是什么?
await 是一个表达式,其计算结果为 Promise 对象或其他值(换句话说,没有特殊限定,无论如何)。
如果 await 后面没有跟 Promise 对象,则直接执行。
如果 await 后面跟着一个 Promise 对象,它会阻塞后面的代码,Promise 对象解析,然后获取 resolve 的值作为 await 表达式的结果。
await 只能在异步函数中使用
上面使用setTimeout来模拟异步操作,我们使用async/await来实现。
async function fn() {let time1 = 0;let time2 = await fn1(time1);let time3 = await fn2(time2);let res = await fn3(time3);console.log(`result is ${res}`);
}fn();
输出结果和上面的 Promise 实现是一样的,但是 async/await 的代码结构看起来更清晰,几乎和同步写法一样优雅。
async/await的优点和缺点
优点:内置执行器,语义更好,适用性更广。
缺点:误用 await 可能会导致性能问题,因为 await 会阻塞代码。
相关文章:
必看!总结5种JavaScript异步解决方案
1.回调 回调简单地理解为一个函数作为参数传递给另一个函数,回调是早期最常用的异步解决方案之一。 回调不一定是异步的,也不直接相关。 举个简单的例子: function f1(cb) {setTimeout(() > {cb && cb();}, 2000); }f1(() >…...

JUC并发编程高级篇第四章之ThreadLocal(人手一份,天下安)
文章目录1、ThreadLocal的简介1.1、常见的面试题(也是本次的讲解的内容)1.2、什么是ThreadLocal1.3、ThreadLocal的所用1.4、没有出现ThreadLocal前后的变化1.5、ThreadLocal代码示例1.6、阿里巴巴对ThreadLocal的使用要求1.7、ThreadLocal的源码分析2、ThreadLocal…...

dump 定位分析
在缺少pdb的时候如何分析dump? windbgidaWindbg定位崩溃位置 通过windbg打开dump,并且分析dump !analyze -v 分析: 分析dump: !analyze -v错误原因:读取空指针错误线程:00001e04,可通过命令…...

(十二)排序算法-插入排序
1 基本介绍 1.1 概述 插入排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。 插入排序的工作方式非常像人们排序一手扑克牌一样。开始时,我们的左手为空并且桌子上的牌面朝下。然后,…...
elasticsearch 认知
1.大数据领域需要解决以下三个问题 如何存储数据 传统的关系数据库(MySQL、Oracle、和Access等)主导了20世纪的数据存储模式,但当数据量达到太字节级,甚至拍字节级时,关系型数据库表现出了难以解决的瓶颈问题。为了解决…...

《人体地图》笔记
《人体地图》 坂井建雄 著 孙浩 译 腹部通向大腿的隧道 腹部与大腿的分界点是大腿根部,即是腹股沟。 腹壁肌肉连结在腹股沟韧带上,腹壁肌肉包括三层,分别为腹外斜肌、腹内斜肌和腹横肌,每块肌肉都有一个张开的小孔,…...

java基础集合面试题
什么是集合 集合就是一个放数据的容器,准确的说是放数据对象引用的容器 集合类存放的都是对象的引用,而不是对象的本身 集合类型主要有3种:set(集)、list(列表)和map(映射)。 集合的特点 集合的特点主要有如下两点&…...
Vue学习-Vue入门
Vue学习 一、Vue入门 1、 引入Vue Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库…...

【项目】bxg基于SaaS的餐掌柜项目实战(2023)
基于SaaS的餐掌柜项目实战 餐掌柜是一款基于SaaS思想打造的餐饮系统,采用分布式系统架构进行多服务研发,共包含4个子系统,分别为平台运营端、管家端(门店)、收银端、小程序端,为餐饮商家打造一站式餐饮服务…...

灌区流量监测设备-中小灌区节水改造
系统概述 灌区信息化管理系统主要对对灌区的水情、雨情、土壤墒情、气象等信息进行监测,对重点区域进行视频监控,同时对泵站、闸门进行远程控制,实现了信息的测量、统计、分析、控制、调度等功能。为灌区管理部门科学决策提供了依据…...

SpringBoot2核心功能 --- 指标监控
一、SpringBoot Actuator 1.1、简介 未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。 <dependency><gro…...
python实战应用讲解-【numpy数组篇】常用函数(三)(附python示例代码)
目录 Python numpy.repeat() Python numpy.tile() Python numpy.asarray_chkfinite() Python numpy.asfarray() Python numpy.asfortranarray() Python numpy.repeat() Python numpy.repeat()函数重复数组中的元素 – arr. 语法 : numpy.repeat(arr, repetitions, axis …...

DIN论文翻译
摘要 在电子商务行业,利用丰富的历史行为数据更好地提取用户兴趣对于构建在线广告系统的点击率(CTR)预测模型至关重要。关于用户行为数据有两个关键观察结果:i) 多样性(diversity)。用户在访问电子商务网站时对不同种类的商品感兴趣。ii) 局部激活(local…...

python列表,元组和字典
1、python列表 1.1.列表的定义 list是一种有序的集合、基于 链表实现,name[ ] ,全局定义:list2list([ ])。 1.2下标索引 python不仅有负索引也有正索引。正索引从0开始,负索引从-1开始。这两个可以混用,但指向还是那个位置 a[0]a[-9]//length为10的数组a1.3列表的切片 列表可…...

300元左右的蓝牙耳机哪个好?300左右音质最好的蓝牙耳机
无线耳机是人们日常生活中必不可少的设备,无论是听音乐化石看电影都能获得身临其境的感觉,由于科技真在发展中,不断地的发生变化,百元价位就可以感受到不错的音色,下面小编整理了几款300左右音质表现不错的蓝牙耳机。 …...

【消息队列】聊一下生产者消息发送流程
消息发送流程 1.生产者main线程调用send发送消息,先走拦截器,然后会将消息进行序列化,然后选择对应的分区器,将消息发送到RecordAccumulator中,默认是32m 2.Sender线程会异步读取,要不数据达到batch的大小 …...

特斯拉和OpenAI的加持,马斯克简直人生赢家
赢家已定 商人行事,最重要的因素之一是利益驱动。这里,最服“马斯克”。 以马斯克为首的特斯拉公司周日宣布,将在上海新建一家超级工厂,专门生产该公司的储能产品Megapack。签约的特斯拉储能超级工厂项目也是该公司在美国本土以…...

优维低代码:第三方接口接入
优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大运维人提供一个技术交流与学习的平台。 连载…...
SQL 177. 第N高的薪水
SQL 177. 第N高的薪水数据需求解决方法1方法2题目 : https://leetcode.cn/problems/nth-highest-salary/ 数据 Create table If Not Exists Employee (Id int comment 主键列, Salary int comment 工资 );Truncate table Employee;insert into Employee (id, sala…...

14天手撸交互式问答数字人直播教程-课程计划
一、课程计划 二、时间安排 第01天:交互式问答数字人发展现状 从一个真实案例开始,介绍当前主流的交互式数字人平台,需求和应用场景,引入交互式数字人的交互流程和关键技术。后续整个直播系列的内容安排。 第02天:音…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...