General solution for pre-emptive background work scheduling on javascript

半腔热情 提交于 2019-12-11 14:59:45

问题


Here is the scenario: When my web app starts, I want to load data from several tables in local storage (using indexedDB). I delegate this work to a web worker. It will load each table in turn, and fire a message with the data as it loads each one. On the main thread, a listener will receive the message and store the data in a cache.

But let's say the user presses a button to view the data for a specific table. The app calls a function that checks the cache, and sees that the data for that table has not been loaded yet.

How does this function wait until the data for that table has been cached so that it can return the data? Even more important, what if the table is scheduled to be loaded last? How can this function send a message to the web worker to prioritize loading that specific table so that its data will available as soon as possible?

What is a general pattern for a clean solution to this pre-emptive scheduling problem? I would like to avoid polling if at all possible.


回答1:


The Worker may use an asynchronous queue that contains all the tables to be loaded and is sorted after a certain priority, so you can priorize certain tables and they get sorted to the front of the table. As you havent shown a real implementation here is a more generalized version:

 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);
  }
}

Note: If the task is not asynchronous you should use sth like setTimeout(next, 0) to allow the process messaging to interrupt it...


A sample implementation could be an image loader:

 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");


来源:https://stackoverflow.com/questions/48794471/general-solution-for-pre-emptive-background-work-scheduling-on-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!