【若川视野 x 源码共读】第32期 | yocto-queue 队列 链表

1,064 阅读2分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。

yocto-queue 处理什么问题?

引用该yocto-queue的一句话:

You should use this package instead of an array if you do a lot of Array#push() and Array#shift() on large arrays, since Array#shift() has linear time complexity O(n) while Queue#dequeue() has constant time complexity O(1). That makes a huge difference for large arrays. 针对 先进先出 这种场景,数组Array#shift()所需的时间复杂度较高O(n)(需要将后面的元素向前移动)。yocto-queue 内部通过链表的实现方式,将复杂度降到O(1),从而优化该场景下的性能。

image.png

阅读该源码可以学到什么?

内部怎么实现的?

Node节点实现

class Node {
    value;// 存储当前值
    next;// 存储下一个节点指针

    constructor(value) {
            this.value = value;
    }
}

整体API

export default class Queue {
    #head;// 指向头指针
    #tail;// 指向当前节点
    #size;// 当前队列元素个数

    constructor() {
            this.clear();
    }
    // 入队
    enqueue(val) {}
    // 出队
    dequeue() {}
    // 清空
    clear() {}
    // 当前队列元素个数
    get(){}

队列API实现

enqueue

enqueue(value) {
        const node = new Node(value);
        
        if (this.#head) {
        // tail.next 指向下一个节点,tail指向当前节点(当前value所在的节点)
                this.#tail.next = node;
                this.#tail = node;
        } else {
        // 首次入队,head 和 tail 都指向第一个节点
                this.#head = node;
                this.#tail = node;
        }
        // 队列元素个数 + 1
        this.#size++;
}

dequeue

dequeue() {
    // 获取头结点
    const current = this.#head;
    // 空队列,直接返回
    if (!current) {
            return;
    }
    // 头结点指向下一个节点
    this.#head = this.#head.next;
    // 队列元素个数减一
    this.#size--;
    return current.value;
}

clear

clear() {
    // 直接置空操作
    this.#head = undefined;
    this.#tail = undefined;
    this.#size = 0;
}

Symbol.iterator使用

Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。 我们看看yocto-queue内部是怎么实现的:

* [Symbol.iterator]() {
    let current = this.#head;
    // 通过循环,不断挪动指针获取到值
    while (current) {
            yield current.value;
            current = current.next;
    }
}

通过上述实现,我们可以通过for...of获取到队列中的值

const queue = new Queue();
queue.enqueue('🦄');
queue.enqueue('🌈');
console.log([...queue]); // 输出:['🦄', '🌈']

ava 单元测试

  • 官网:github.com/avajs/ava
  • 简介:一个轻量高效、高并发、简单测试语法的测试运行库。
  • demo:
        import test from 'ava';
      
        test('foo', t => {
                // 测试通过
                t.pass();
        });
    
        test('bar', async t => {
                const bar = Promise.resolve('bar');
                // 判断两个值是否相等
                t.is(await bar, 'bar');
        });
    

从yocto-queue源码中可以看出,主要针对暴露的API进行功能测试,也为开发者了解其API的使用。 image.png

总结

从yocto-queue源码中,可以学习队列实现方式以及对应API的单元测试的完整过程;了解到链表与数组的一些区别以及Symbol.iterator的使用场景。