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

一文彻底搞清 Iterator(遍历器)概念及用法

目录

一、由来及意义

二、具体实现流程

三、具有默认 Iterator 接口的数据结构

四、调用 Iterator 接口的场合

五、总结


一、由来及意义

Javascript中表示“集合”的数据结构,主要是 ArrayObjectMapSet 这四种数据集合,除此之外,它们相互之间还可以组合使用,例如Array的成员是MapMap的成员是Object等。因此Javascript得需要一种统一的接口机制,来处理所有不同的数据结构。

遍历器(Iterator)就是这样一种机制。它是一种接口,可以为各种不同的数据结构提供一种访问机制(访问接口),任何数据结构部署Iterator接口,就可以完成该数据结构成员的遍历操作(Iterator 接口主要供for...of使用)。

二、具体实现流程

Iterator的遍历过程:

1. 创建一个指针对象,指向数据解构的起始位置。

2. 第一次调用指针对象的next()方法,指针指向数据结构的第一个成员。

3. 第二次调用指针对象的next()方法,指针指向数据结构的第二个成员。

4. 不停调用指针对象的next()方法,直到它指向数据结构结束的位置。(类似于C语言中的链表)

每一次调用next方法,都会返回数据结构中被指针指向的成员的信息。该信息为一个对象,其中包含valuedone两个属性的对象{ value: something , done: false }value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束(done:false:表示循环还没有结束,done:true :表示循环结束了)。

模拟next方法返回值例子:

下面代码定义了一个makeIterator函数,它是一个遍历器生成函数,作用就是返回一个遍历器对象。对数组['前端','收割','机']执行这个函数,就会返回该数组的遍历器对象(即指针对象)goodjob

function makeIterator(array){var index = 0;//形成闭包保存指针指向位置index,通过三元表达式返回当前信息对象。return {next: function(){return index < array.length ? {value: array[index++], done: false} : {value: undefined, done: true};}}
}var goodjob = makeIterator(['前端','收割','机'])goodjob.next()//  {value: '前端', done: false}
goodjob.next()//  {value: '收割', done: false}
goodjob.next()//  {value: '机',  done: false}
goodjob.next()//  {value: undefined, done: false}

由于 Iterator 只是把接口规格加到数据结构之上,所以,遍历器与它所遍历的那个数据结构,实际上是分开的,完全可以写出没有对应数据结构的遍历器对象,或者说用遍历器对象模拟出数据结构。 

另一种写法:

function makeIterator(array) {var index = 0; //形成闭包保存指针指向位置index,通过if分支语句返回当前信息对象。return {next: function() {var result = {value: undefined, done: true};if (index < array.length) {result = { value: array[index++], done: false };}return result;}};
}// 使用示例
var iterable = makeIterator([1, 2, 3]);
console.log(iterable.next().value); // 输出: 1
console.log(iterable.next().value); // 输出: 2
console.log(iterable.next().value); // 输出: 3
console.log(iterable.next().value); // undefined,迭代结束

makeIterator 这个函数的目的是创建一个迭代器对象,该对象可以遍历传入的数组。在JavaScript中,一个迭代器对象需要实现next方法,该方法在每次调用时返回数组的下一个元素。

在这个解决方案中,makeIterator函数通过返回一个对象,该对象具有一个next方法,来创建一个迭代器。每次调用next方法时,它都会返回数组中的下一个元素,直至遍历完成,此时done属性为true,value属性为undefined。这是符合ES6中Iterable和Iterator协议的定义。 

三、具有默认 Iterator 接口的数据结构

Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。

因此,当某种数据结构具有Iterator 接口,即表示该数据结构是可遍历的(iterable)。

默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内。

const object1 = {[Symbol.iterator] : function () {return {next: function () {return {value: 1,done: true};}};}
};

对象object1是可遍历的(iterable),因为具有Symbol.iterator属性。执行这个属性,会返回一个遍历器对象。该对象的根本特征就是具有next方法。每次调用next方法,都会返回一个代表当前成员的信息对象,具有valuedone两个属性。

凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。即不用任何处理,就可以被for...of循环遍历。

原生具备 Iterator 接口的数据结构:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • NodeList 对象
  • 函数的 arguments 对象

数组的Symbol.iterator属性:

let arr = ['前端', '收割', '机'];
let iterator = arr[Symbol.iterator]();  //因为arr中属性Symbol.iterator返回的是一个函数,//所以在[Symbol.iterator]后面添加(),使函数执行,返回一个遍历器对象iterator.next() // { value: '前端', done: false }
iterator.next() // { value: '收割', done: false }
iterator.next() // { value: '机', done: false }
iterator.next() // { value: undefined, done: true }

数组通过for of调用iterator接口生成的遍历器

const arr = ['前端', '收割', '机'];for(let v of arr) {console.log(v); // 前端 收割 机
}

Map通过for of调用iterator接口生成的遍历器

var handsome = new Map();
handsome.set("GuangHui", "1handsome");
handsome.set("JiaHao", "2handsome");
handsome.set("NingDong", 666);
for (var [name, value] of handsome) {console.log(name + ": " + value);
}
// GuangHui: 1handsome
// JiaHao: 2handsome
// NingDong: 666

Set 通过for of调用iterator接口生成的遍历器

var handsome = new Set(["GuangHui", "JiaHao", "NingDong"]);
for (var boy of handsome) {console.log(boy);
}
// GuangHui
// JiaHao
// NingDong

类数组对象通过for of调用iterator接口生成的遍历器

// 字符串
let str = "前端收割机";for (let s of str) {console.log(s); // 前 端 收 割 机
}// DOM NodeList对象
let paras = document.querySelectorAll("p");for (let p of paras) {p.classList.add("前端收割机");
}// arguments对象
function printArgs() {for (let x of arguments) {console.log(x);}
}
printArgs('前端', '收割机');
// '前端'
// '收割机'

对于不具备Iterator接口的数据结构(主要是对象)都需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。

原因:对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换。

下面是为对象添加 Iterator 接口的例子:

let object2 = {data: [ '前端', '收割','机'],[Symbol.iterator]() {const self = this; //将this指向赋予selflet index = 0;     //初始遍历下标return {next() {if (index < self.data.length) {return {value: self.data[index++], //每次调用,遍历下标自增1done: false};} else {return { value: undefined, done: true }; //遍历结束返回该对象}}};}
};

对于类似数组的对象(存在数值键名和length属性),部署 Iterator 接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的 Iterator 接口。

let object3 = {0: '前端',1: '收割',2: '机',length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator] //直接引用数组构造函数prototype中的 Symbol.iterator属性
};
for (let item of object3) {console.log(item); // '前端', '收割', '机'
}

注意,普通对象部署特定数据结构的Symbol.iterator方法,并无效果。例如普通对象部署数组的Symbol.iterator方法。

let object4 = {  //该对象不存在数值键名a: '前端',b: '收割',c: '机',length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of object4) {console.log(item); // undefined, undefined, undefined
}

如果Symbol.iterator方法对应的不是遍历器生成函数(即会返回一个遍历器对象),解释引擎将会报错。

var object5 = {};obj[Symbol.iterator] = () => '前端收割机';  //返回的是一个字符串[...object5]  // TypeError: [] is not a function

四、调用 Iterator 接口的场合

除了for...of循环,某些场景会默认调用 Iterator 接口(即Symbol.iterator方法)

番外:一文带你了解JavaScript中的for...of循环

注意事项


尽管 for...of 循环非常方便和实用,但在使用时仍需要注意一些细节和注意事项,以避免潜在的 bug 或错误。

首先,需要注意的是,for...of 循环只能用于遍历实现了迭代器协议的对象。如果我们尝试使用 for...of 循环遍历一个不支持迭代器协议的对象,会导致 TypeError 错误。

其次,需要注意的是,for...of 循环只能访问迭代器的值,而不能访问迭代器的索引或键。如果我们需要访问迭代器的索引或键,可以考虑使用其他循环结构,如 for 循环或 forEach 方法。

最后,需要注意的是,for...of 循环中的迭代变量是一个常量,其值在每次迭代中都会被重新赋值。因此,我们不能在循环中修改迭代变量的值,否则会导致错误。

解构赋值

let set = new Set().add('前端').add('收割').add('机'); //Set通过add方法进行链式添加值let [one,two] = set;
// x='前端'; y='收割'let [one, ...two] = set;
// one='前端'; two=['收割','机'];

扩展运算符

// 例一
var str = '前端收割机';
[...str] //  ['前','端','收','割','机']// 例二
let arr = ['是', '靓'];
['我', ...arr, '仔']
// ['我', '是', '靓', '仔']

扩展运算符内部就调用 Iterator 接口,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,通过扩展运算符,转为数组。

yield*

yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

let generator = function* () {yield "我";yield* ["是","靓","仔"];yield "啊";
};var iterator = generator();iterator.next() // { value: "我", done: false }
iterator.next() // { value: "是", done: false }
iterator.next() // { value: "靓", done: false }
iterator.next() // { value: "仔", done: false }
iterator.next() // { value: "啊", done: false }
iterator.next() // { value: undefined, done: true }

Array.from()

Array.from()函数以类数组形式输入值,Array.from()函数调用Iterator接口,将输入的类数组转化成数组

let arrayLike = {0: '前端', 1: '收割',2: '机',3: ['GuangHui','JiaHao','NingDong'],'length': 4
}
let arr = Array.from(arrayLike)
console.log(arr) // ['前端','收割','机',['GuangHui','JiaHao','NingDong']]

Map(), Set(), WeakMap(), WeakSet()

Map构造函数以数组形式输入键值对,新建Map对象时,Map构造函数调用Iterator接口,遍历存入键值对

var goodJob  = new Map([['前端',1],['收割机',2]]) 

Promise.all()

Promise.all()函数以Promise数组形式输入值,Promise.all()函数调用Iterator接口,将promise请求遍历执行。

const p = Promise.all([p1, p2, p3]);

Promise.all()方法接受一个数组作为参数,p1p2p3都是 Promise 实例,如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

Promise.race()

Promise.race()函数以Promise数组形式输入值,Promise.race()函数调用Iterator接口,将promise请求遍历执行。

const p = Promise.race([p1, p2, p3]);

Promise.race()方法接受一个数组作为参数,p1p2p3都是 Promise 实例,如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.race()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

● 补充:Generator 函数与 Iterator 接口的关系:

对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。

五、总结

▲遍历器(Iterator)可以为各种不同的数据结构提供一种访问机制(访问接口),任何数据结构部署Iterator接口,就可以完成该数据解构成员的遍历操作(Iterator 接口主要供for...of使用)。

Iterator的遍历过程:创建一个指针对象,指向数据解构的起始位置。不停调用指针对象的next()方法,指针往后移动,直到它指向数据结构结束的位置。每一次调用next方法,都会返回数据结构中被指针指向的成员的信息{ value: something , done: false }。 

ArrayMapSetStringTypedArrayNodeList 对象,函数的 arguments 对象为原生具备 Iterator 接口的数据结构。

调用 Iterator 接口的场合:for...of循环、解构赋值扩展运算符yield*Array.from()Map()Set()、 WeakMap()、 WeakSet()Promise.all()Promise.race()

✔ 参考资料

JavaScript中Iterator迭代器接口和循环_脚本之家 | Iterator(遍历器)接口概念以及用法

JavaScript中Iterator迭代器接口和循环 - Python技术站 | JS– Iterator接口 | JS_ES6 - Iterator

相关文章:

一文彻底搞清 Iterator(遍历器)概念及用法

目录 一、由来及意义 二、具体实现流程 三、具有默认 Iterator 接口的数据结构 四、调用 Iterator 接口的场合 五、总结 一、由来及意义 Javascript中表示“集合”的数据结构&#xff0c;主要是 Array、Object、Map、Set 这四种数据集合&#xff0c;除此之外&#xff0c;…...

稀疏矩阵的三元组表表示法及其转置

1. 什么是稀疏矩阵 稀疏矩阵是指矩阵中大多数元素为零的矩阵。 从直观上讲&#xff0c;当元素个数低于总元素的30%时&#xff0c;这样的矩阵被称为稀疏矩阵。 由于该种矩阵的特点&#xff0c;我们在存储这种矩阵时&#xff0c;如果直接采用二维数组&#xff0c;就会十分浪费…...

docker安装rabbitMQ,并且创建账号

# 创建docker容器启动,挂到后台运行 docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.13-management # 打开防火墙 sudo firewall-cmd --zonepublic --add-port5672/tcp --permanent sudo firewall-cmd --zonepublic --add-port15672/tcp --permanent s…...

wireshark解析grpc/protobuf的方法

1&#xff0c;wireshark需要安装3.20以上 下载地址&#xff1a;https://www.wireshark.org/ 2&#xff0c;如果版本不对&#xff0c;需要卸载&#xff0c;卸载方法&#xff1a; sudo rm -rf /Applications/Wireshark.app sudo rm -rf $HOME/.config/wireshark sudo rm -rf /…...

软件测试用例(2)

具体的设计方法 -- 黑盒测试 因果图 因果图是一种简化的逻辑图, 能直观地表明程序的输入条件(原因)和输出动作(结果)之间的相互关系. 因果图法是借助图形来设计测试用例的一种系统方法, 特别适用于被测试程序具有多种输入条件, 程序的输出又依赖于输入条件的各种情况. 因果图…...

集群式无人机仿真环境和数据集

仿真环境和数据集 Quick StartAcknowledgementsSwarmSim Quick Start Compiling tests passed on 20.04 with ros installed. You can just execute the following commands one by one. # Download the Simulator and run it wget https://cloud.tsinghua.edu.cn/library/34…...

IPSec VPN

IP Security,IP安全 1、特点 L3的VPN 缺:不支持组播、配置复杂、延迟增加、资源消耗较多 优:具备访问控制、密码学四个维度、抗重放打击 2、组件 ①安全协议 1)验证头技术(AH) IP协议号51 提供数据完整性检查,身份验证,抗重放攻击 无法做数据的机密性 AH的完…...

docker部署nacos,单例模式(standalone),使用内置的derby数据库,简易安装

文章目录 前言安装创建文件夹docker指令安装docker指令安装-瘦身版 制作docker-compose.yaml文件查看页面 前言 nacos作为主流的服务发现中心和配置中心&#xff0c;广泛应用于springcloud框架中&#xff0c;现在就让我们一起简易的部署一个单例模式的nacos&#xff0c;版本可…...

systemd监听服务配置文件更新自动重启服务

背景&需求 需要频繁更改一个服务的配置文件进行测试 实现 配置服务的systemd文件 vim /lib/systemd/system/xxx.service [Unit] Descriptionxxx daemon, A rule-based proxy in Go.[Service] Typesimple ExecStart/opt/xxx/xxx-d /etc/xxx/ Restartalways[Install] Wan…...

【yy讲解PostCSS是如何安装和使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…...

YOLO电动车检测识别数据集:12617张图像,yolo标注完整

YOLO电动车检测识别数据集&#xff1a;12617张图像&#xff0c;电动车一类&#xff0c;yolo标注完整&#xff0c;部分图像应用增强。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 需要此数据集或其他任何数据集请私信...

从汇编看函数调用

文章目录 函数调用流程栈相关寄存器及的作用简介寄存器功能指令功能 栈函数的括号{}正括号反括号 参数传递传值&#xff0c;变量不可改传指针&#xff0c;变量可改C 传引用 函数调用实例 函数调用流程 目标&#xff1a;函数调用前后栈保持不变 保存main函数的寄存器上下文移…...

node.js的错误处理

当我打开一个不存在的文件时&#xff0c;错误如下&#xff1a; 在读取文件里面写入console.log&#xff08;err&#xff09;&#xff0c;在控制台中可以看到我的错误代码类型&#xff1a;文件不存在的错误代码 ENOENT。见更多错误代码---打开node.js官方API文档Error 错误 | N…...

shell的编写

文章目录 1.框架2.命令行3.获取用户命令字符串4.命令行字符串分割5.执行命令和内建命令6.完整代码&#xff1a; 1.框架 我们知道shell是一直存在的&#xff0c;所以首先我们第一步就是要搭建一个框架&#xff0c;使其一直存在。 那么也很简单&#xff0c;一个while循环就可以完…...

css心跳动画

图标引入 <img class"icon" src"heart.svg" alt"" srcset""> CSS代码 <style>.icon {animation:bpm 1s linear,pulse 0.75s 1s linear infinite;}keyframes pulse {from,75%,to {transform: scale(1);}25% {transform:…...

在 Amazon Timestream 上通过时序数据机器学习进行预测分析

由于不断变化的需求和现代化基础设施的动态性质&#xff0c;为大型应用程序规划容量可能会非常困难。例如&#xff0c;传统的反应式方法依赖于某些 DevOps 指标&#xff08;如 CPU 和内存&#xff09;的静态阈值&#xff0c;而这些指标在这样的环境中并不足以解决问题。在这篇文…...

【智能排班系统】快速消费线程池

文章目录 线程池介绍线程池核心参数核心线程数&#xff08;Core Pool Size&#xff09;最大线程数&#xff08;Maximum Pool Size&#xff09;队列&#xff08;Queue&#xff09;线程空闲超时时间&#xff08;KeepAliveTime&#xff09;拒绝策略&#xff08;RejectedExecutionH…...

C语言——内存函数

前言&#xff1a; C语言中除了字符串函数和字符函数外&#xff0c;还有一些函数可以直接对内存进行操作&#xff0c;这些函数被称为内存函数&#xff0c;这些函数与字符串函数都属于<string.h>这个头文件中。 一.memcpy&#xff08;&#xff09;函数 memcpy是C语言中的…...

ideaSSM图书借阅管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 SSM 图书借阅管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码 和数据库&#xff0c;系统主…...

普联一面4.2面试记录

普联一面4.2面试记录 文章目录 普联一面4.2面试记录1.jdk和jre的区别2.java的容器有哪些3.list set map的区别4.get和post的区别5.哪个更安全6.java哪些集合类是线程安全的7.创建线程有哪几种方式8.线程的状态有哪几种9.线程的run和start的区别10.什么是java序列化11.redis的优…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...