I think you can do without locking by taking advantage of the fact that javascript is single-threaded in context, even with the asynchronous chrome.storage API. Until you use chrome.storage.sync, that is - if there are or are not changes from the cloud, I think that all bets are disabled.
I would do something like this (wrote off the cuff, didn't test, didn't handle the errors):
var getTask = (function() { // Private list of requests. var callbackQueue = []; // This function is called when chrome.storage.local.set() has // completed storing the updated task list. var tasksWritten = function(nComplete) { // Remove completed requests from the queue. callbackQueue = callbackQueue.slice(nComplete); // Handle any newly arrived requests. if (callbackQueue.length) chrome.storage.local.get('tasks', distributeTasks); }; // This function is called via chrome.storage.local.get() with the // task list. var distributeTasks = function(items) { // Invoke callbacks with tasks. var tasks = items['tasks']; for (var i = 0; i < callbackQueue.length; ++i) callbackQueue[i](tasks[i] || null); // Update and store the task list. Pass the number of requests // handled as an argument to the set() handler because the queue // length may change by the time the handler is invoked. chrome.storage.local.set( { 'tasks': tasks.slice(callbackQueue.length) }, function() { tasksWritten(callbackQueue.length); } ); }; // This is the public function task consumers call to get a new // task. The task is returned via the callback argument. return function(callback) { if (callbackQueue.push(callback) === 1) chrome.storage.local.get('tasks', distributeTasks); }; })();
This is where requests from consumers are stored as callbacks in a queue in local memory. When a new request arrives, the callback is added to the queue, and iff selects the task list, this is the only request in the queue. Otherwise, we can assume that the queue is already being processed (this is an implicit lock that allows only one execution chain to access the list of tasks).
When a task list is selected, tasks are distributed by request. Please note that there may be more than one request if there is more profit before the sample is completed. This code simply passes the null value to the callback if there are more requests than jobs. Instead, block requests until more tasks arrive, do not make callbacks and reload the request when adding tasks. If tasks can be dynamically performed as well as consumed, remember that race conditions must also be averted, but not shown here.
It is important to prevent the task list from being read again until the updated task list is saved. To do this, requests are not removed from the queue until the update is completed. Then we must be sure to process any requests received at this time (a short circuit to the call to chrome.storage.local.get () is possible, but I did it this way for simplicity).
This approach should be quite effective in the sense that it should minimize updates to the task list while still responding as quickly as possible. There is no explicit lock or wait. If you have task users in other contexts, configure the chrome.extension message handler, which calls the getTask () function.
rhashimoto
source share