我正在参与掘金会员专属活动-源码共读第一期,点击参与
前言
昨天刚学完 omit 的源码,今天趁着学习源码的热度还没结束,来学习一下另一个我之前未接触过的东西 yocto-queue。
yocto-queue 介绍
那么 yocto-queue 是什么呢?它有什么功能呢?查阅资料可得,对于数据比较多的数组,如果需要频繁地使用 push 和 shift 方法,那么可以使用 yocto-queue 来代替数组。因为shift 操作具有 O(n) 的时间复杂度,而通过 yocto-queue,只需要 O(1) 的时间复杂度。
说到 yocto-queue,不得不可以提到队列(毕竟名字中就带有 queue)。队列的工作原理是先进先出(FIFO),它是一个有序的元素列表,其中一个元素插入到队列的末尾,然后从队列的前面移除。
分析源码
介绍了它的一些基本信息,现在开始分析一下它们的源码部分。进入到 github,找到它的源码中的 package.json 部分,发现源码部分在 ./index.js 文件下。
我们进入到关键源码实现部分,代码不多,才六十多行,代码如下:
class Node {
value;
next;
constructor(value) {
this.value = value;
}
}
export default class Queue {
#head;
#tail;
#size;
constructor() {
this.clear();
}
enqueue(value) {
const node = new Node(value);
if (this.#head) {
this.#tail.next = node;
this.#tail = node;
} else {
this.#head = node;
this.#tail = node;
}
this.#size++;
}
dequeue() {
const current = this.#head;
if (!current) {
return;
}
this.#head = this.#head.next;
this.#size--;
return current.value;
}
clear() {
this.#head = undefined;
this.#tail = undefined;
this.#size = 0;
}
get size() {
return this.#size;
}
* [Symbol.iterator]() {
let current = this.#head;
while (current) {
yield current.value;
current = current.next;
}
}
}
Node
源码一开始就创建一个节点类 Node。节点里有两个属性, value 表示节点的值,next 是一个指向下一节点的指针,里面还有一个构造函数。
class Node {
value;
next;
constructor(value) {
this.value = value;
}
}
Queue
在 Queue 中,创建 head 和 tail 头尾指针,并定义 size 来记录大小。每次遍历的时候先找到头结点,然后通过每个结点的 next 指针往后走。这样一看是不是又很像链表。
注:head 指向头节点,用于模拟 shift 来删除第一个元素;tail 指向尾节点,用于模拟 push 向末尾添加新元素。
clear
然后这里还定义了 clear 方法。如下所示:
clear() {
this.#head = undefined;
this.#tail = undefined;
this.#size = 0;
}
clear 方法对实例的三个属性做了初始化。其中,把指针初始化为 undefined,表示一开始没有节点,将 size 初始化为0,表示是个空链表。
迭代器
这里的链表遍历使用了迭代器,采用了 [Symbol.iterator] 这个方法。之所以会用到这个方法来遍历,是为了让对象可迭代,而这个方法就可以达到此要求。
* [Symbol.iterator]() {
let current = this.#head;
while (current) {
yield current.value;
current = current.next;
}
使用 yocto-queue
看完源码后,我们来通过简单的练习更好地看清楚它发挥的作用。我创建了一个 react 项目,写了一个关于使用 yocto-queue 的 demo,代码如下所示:
import Queue from "./index";
const queue = new Queue();
queue.enqueue("a");
queue.enqueue("b");
console.log(queue.dequeue());
console.log(...queue);
console.log(queue.size);
for (let q of queue) {
console.log(q);
}
queue.clear();
function App() {
return (
<div className="App"></div>
)
}
export default App
index 里面是 yocto-queue 源码,相当于引入 yocto-queue 包。然后分别调用了源码中的关键功能函数,并打印结果。
最终打印结果如下:
总结
以上就是我分享整个 yocto-queue 源码的过程。整体看下来代码其实并不长,但是作用却很大,非常实用。它既有数组的知识,又有队列的知识,也有链表的知识。关于数组的知识,可以看看我之前的这篇文章。
虽然目前我还没机会用到它,但是相信以后会有机会使用到它的。对于这个库,它的作用还是很大的。希望以后还能继续研究它。