代码之家  ›  专栏  ›  技术社区  ›  prmph

javascript上抢占式后台工作调度的通用解决方案

  •  0
  • prmph  · 技术社区  · 7 年前

    以下是场景: 当我的web应用启动时,我想从本地存储中的几个表加载数据(使用indexedDB)。我将这项工作委托给一名网络工作者。它将依次加载每个表,并在加载每个表时发出一条包含数据的消息。在主线程上,侦听器将接收消息并将数据存储在缓存中。

    但假设用户按下按钮查看特定表的数据。该应用程序调用一个检查缓存的函数,发现该表的数据尚未加载。

    该函数如何等待该表的数据被缓存,以便返回数据?更重要的是,如果表计划在最后加载,该怎么办?此函数如何向web worker发送消息,以确定加载该特定表的优先级,从而使其数据尽快可用?

    对于这种先发制人的调度问题,清洁解决方案的一般模式是什么?我希望尽可能避免投票。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Jonas Wilms    6 年前

    工作进程可以使用异步队列,该队列包含要加载的所有表,并按照一定的优先级进行排序,因此您可以对某些表进行优先级排序,然后将它们排序到表的前面。由于您尚未展示真正的实现,这里有一个更通用的版本:

     class AsyncPriorityQueue {
       constructor(task){
         this.task = task;
         this.queue = [];
       }
    
       push(element, priority = 0){
         const pos = this.queue.findIndex(el => el.priority < priority) + 1;
         this.queue.splice(pos, 0, {element, priority});
    
         if(this.running) return;
         this.running = true;
         this._run();
       }
    
       prioritize(element, priority = 10){
         const pos = this.queue.findIndex(el => el.element === element);
         if(pos != -1) this.queue.splice(pos, 1);
    
         this.push(element, priority);
      }
    
       async _run(){
         while(this.queue.length)
            await this.task(this.queue.shift().element);
      }
    }
    

    注意:如果任务不是异步的,那么应该使用 setTimeout(next, 0) 要允许进程消息传递中断它。。。


    示例实现可以是图像加载器:

     class ImageLoader extends AsyncPriorityQueue  {
       constructor(){
         super(function task(url){
           const img = new Image();
           img.src = url;
           return new Promise(res => img.onload = res);
         });
       }
    }
    
    const loader = new ImageLoader;
    
     loader.push("a.jpg");
     loader.push("b.jpg", 1); // a bit more important
     // Oh, wait:
     loader.prioritize("a.jpg");