Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I wait for a javascript function to return a response using Chrome.storage API?

I am trying to use the following code to set and get name value pairs in a Chrome Extension.

if (!this.Chrome_getValue || (this.Chrome_getValue.toString && this.Chrome_getValue.toString().indexOf("not supported") > -1)) {
    this.Chrome_getValue = function (key, def) {
        chrome.storage.local.get(key, function (result) {
            return result[key];
        });
    };
    this.Chrome_setValue = function (key, value) {
        var obj = {};
        obj[key] = value;
        return chrome.storage.local.set(obj)
    }
}

I am then invoking these as follows:

Chrome_setValue("City", "London");

var keyValue = Chrome_getValue("City");

The problem is the keyValue is always 'undefined' even if I put a 1 second delay in trying to read back the value. I understand this is because the 'chrome.storage.local.get' function is asynchronous.. the following code works fine.

Chrome_setValue("City", "London");

chrome.storage.local.get("City", function (result) {
     alert(result["City"]);
});

Is there any way when binding the keyValue (using get) I can force the code to wait for the function to return a response? Or perhaps I'm approaching this from the wrong angle. Essentially I am looking for a way I can abstract out the set and get methods for handling data within the chrome.storage framework? Ideally two simple functions I can call for setting and retrieving name value pairs.

Before I was using localStorage which was very straightforward.

//Set
localStorage["City"] = "London";

//Get
var keyValue = localStorage["City"];
like image 833
QFDev Avatar asked May 01 '13 10:05

QFDev


2 Answers

QF_D, I'm into educated guesswork here, so be prepared for this not to work first time .....

..... here goes :

if (!this.Chrome_getValue || (this.Chrome_getValue.toString && this.Chrome_getValue.toString().indexOf("not supported") > -1)) {
    this.Chrome_getValue = function (key, def) {
        var dfrd = $.Deferred();
        chrome.storage.local.get(key, function (result) {
            dfrd.resolve(result[key]);
        });
        return dfrd.promise();
    };
    this.Chrome_setValue = function (key, value) {
        var dfrd = $.Deferred();
        var obj = {};
        obj[key] = value;
        var listen = function(changes, namespace) {
            dfrd.resolve(changes[key]);
            chrome.storage.onChanged.removeListener(listen);//remove, to prevent accumulation of listeners
        }
        chrome.storage.onChanged.addListener(listen);
        chrome.storage.local.set(obj);
        return dfrd.promise()
    }
}

The get and set functions should thus return jQuery promises. The promise returned by the set function is resolved with a StorageChange object defined here. In general you won't need this object, rather just respond to the promise being resolved.

Everything above is untested. I'm not too sure about :

  • chrome.storage.onChanged..... Should it be chrome.storage.local.onChanged....?
  • .removeListener(). It seems resonable that it should exist if addListener exists, though I can't find any evidence of it.
like image 192
Beetroot-Beetroot Avatar answered Sep 25 '22 00:09

Beetroot-Beetroot


Well, it's essentially because the chrome.storage API is asynchronous. You are facing something which is at the core of JavaScript.

What's executed in the chrome.storage.get callback is not returned by chrome.storage.get. You have 2 ways of dealing with it:

  • deal with the storage value in the callback
  • use the Promise pattern to keep your code feeling synchronous (cf. the previous answer)

You really have to figure out the difference between synchronous and asynchronous.

like image 29
Oncle Tom Avatar answered Sep 26 '22 00:09

Oncle Tom