yocto-queue源码详解

今日学习yocto-queue源码-只有几十行

yocto-queue这个库的使用场景是,当我们需要频繁的进行数组的push或shift操作时,就可以用这个库,因为这个库的时间复杂度是 O(1) ,利用空间换取了时间,并且在p-limit库中,其实就用到了这个库,让我们来看看这个库的源码,代码量也不多,总共也就几十行,有任何分析不对的地方,各位大佬麻烦帮忙指出

class Node {
    /// value;
    /// next;
​
    constructor(value) {
        this.value = value;
​
        // TODO: Remove this when targeting Node.js 12.
        this.next = undefined;
    }
}
​
class Queue {
    // TODO: Use private class fields when targeting Node.js 12.
    // #_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;
        }
    }
}
​
module.exports = Queue;
 

Node

声明了一个Node类,并且接收一个参数value,初始化了实例对象的value和next属性

当我看到valuenext 这两个属性时,顿时感到无比的熟悉,具体是用来干嘛的呢?我们接着往下看

Queue(队列)

声明了一个Queue类,看到这,大概也能猜到,这是一个实现队列的库,constructor函数直接调用了clear函数,也就是说,new调用Queue类时,会初始化实例对象的三个属性

头部指针_head ,尾部指针 _tail,队列长度 _size

clear() {
    this._head = undefined; // 头部指针
    this._tail = undefined; // 尾部指针
    this._size = 0; // 队列长度
}

进入队列

下述代码重点是 this._tail.next = node; 的这段代码, this._head的最后一个next === this._tail ,你只需要能理解这个,下述代码就豁然开朗

每次修改 this._tail.next = node 其实就是在修改head的最后一个next的值

enqueue(value) { // value-> 进入队列的任务
    const node = new Node(value);
    if (this._head) { // 判断有没有头部指针,也就是判断是否是第一个进入队列,(如果第一个进入队列,就会走else)
        this._tail.next = node; // 将尾部指针的next指向新的node ,重点:这里的tail其实跟head的最后一个next的地址是一样的,所以这里的next相当于是 给head的最后一个next赋值,看不懂的话要多看几遍
        this._tail = node; // 将尾部指针指向最新加进来的任务
    } else {
        //第一次进入队列
        this._head = node; // 头部指针指向第一个任务
        this._tail = node; // 尾部指针指向第一个任务
    }
    this._size++; // 增加队列长度
}

退出队列
dequeue() {
    const current = this._head; // 获取头部指针的地址
    if (!current) {
        return;
    }
    // 其实就是把当前头部的任务送出去,并且将指针指向下一个任务
    // 把头部指针的地址切换成下一个的,此步骤切换地址是不会影响current的地址
    this._head = this._head.next; // 退出队列 ,并将拿到排队的任务
    this._size--; // 队列长度-1
    return current.value; 返回退出的任务
}

迭代器

有Symbol.iterator 属性表示可以被for...of 遍历, 加上* 表示是个生成器对象,可以使用yield关键字,yield 右边的值就是每次循环拿到的值

对象一开始是没有Symbol.iterator,所以普通对象是不可被for...of遍历的

* [Symbol.iterator]() {
    let current = this._head;//遍历从头部指针开始
​
    while (current) {
        yield current.value;  // current.value就是每次循环的值
        current = current.next;// 循环的每一项,每次拿完值后,将current修改为下一个指针 ,避免死循环
    }
}
使用
const queue = new Queue()
​
queue.enqueue('你好你好') // 加入队列
console.log(queue.dequeue()) // 退出队列并返回值
'你好你好'
​
// 我们也可以这样做
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
queue.enqueue(4)
queue.enqueue(5)
​
console.log([...queue]) // [1,2,3,4,5]
for (const val of queue) {
  console.log(val)  
}

​总结:

以上就是我分享整个 yocto-queue 源码的过程。整体看下来代码其实并不长,但是作用却很大,非常实用。让我从中学到了数组、队列、指针、链表的知识,对我个人来说作用很大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值