3

设计阻塞队列的缘由是因为在做业务时遇见庞大的资源列表加载问题,我们的业务主要是媒体资源的加载。http 1.0的时候大部分浏览器支持最大并行数量是6个,http 2.0的时候有所提升,HTTP/2.0理论上可以在一个TCP连接上发送无数个HTTP请求。
如果我们一次加载100张图片,那么网络资源抢占严重。如果用户网络环境差,那么资源加载问题就更加严重了。那么我们可以考虑 控制并行的数量,每次资源加载的数量控制,控制加载队列始终在6个以内。
为了解决这个问题,设计了基于promise的阻塞式队列。本质就是一个队列长度有限的生产消费模式。以图片为例子:

class Scheduler {

    constructor(maxCount = 6) {
        this.list = [];
        this.count = 0;
        this.maxCount = maxCount;
    }

    // 添加任务队列
    addTask(promiseCreator) { 
        return new Promise((resolve) => {
            // 添加的时候通知 队列有东西可以消费
            this.list.push(() => {
                return promiseCreator().then(res => {
                    this.count -= 1;
                    // 一个任务做完下一个任务才开始
                    this.consume();
                    resolve(res);
                    return res;
                });
            });
            this.consume();
        });
    }

    provider = (src) => {
        return this.addTask(() => new Promise((resolve, reject) => {
            const img = new  Image();
            img.src = src;
            img.onload = function() {
                // 图片加载成功
                resolve(src);
            }
            img.onerror = function(err) {
                // 图片加载失败
                reject(err);
            }
        }));
    };

    consume() {
        // 最多同时做两个任务
        if(this.count < this.maxCount && this.list.length > 0) {
            this.count += 1;
            const item = this.list.shift();
            item && item();
        } 
    }
}

使用(配合MutationObserver api 来优化图片列表会更佳):

const queue = new Scheduler();
queue.provider('http://xxxxxxxx');
queue.provider('http://xxxxxxxx');
queue.provider('http://xxxxxxxx');
queue.provider('http://xxxxxxxx');
queue.provider('http://xxxxxxxx');
queue.provider('http://xxxxxxxx');
queue.provider('http://xxxxxxxx');

H_H_code
51 声望3 粉丝