0

My chrome.tabs.query code does not seem to execute when looking my extension in the debugger. I'm experimenting with the chrome.storage API to log the number of times articles at nytimes.com are accessed, and since I've added the chrome.storage code at the beginning the debugger seems not to enter the chrome.tabs.query function.

var nytCount = chrome.storage.local.get["nyt"];

// if nytCount doesn't exist in chrome local storage, set to 0
if (nytCount === undefined)
{
    nytCount = 0;
}


/*
* Below is adapted from user Rob W at Stack Overflow (http://stackoverflow.com/questions/10413911/how-to-get-the-currently-opened-tabs-url-in-my-page-action-popup/10417327#10417327)
*
// Gets URL from currently active window (this should all be onload I suspect)*/
chrome.tabs.query({
    // Select active tabs
    active: true,
    // In the current window                              
    windowId: chrome.windows.WINDOW_ID_CURRENT 
}, function(array_of_Tabs) {
    // Since there can only be one active tab in one active window, the array has only one element
    var tab = array_of_Tabs[0];
    var title = tab.title;

    if (title.indexOf("NYTimes.com") !== -1)
    {
        nytCount++;
    }

    // rest of if conditions for those sites that have identifiers in tab titles
});

alert(nytCount);

Any ideas? It worked fine before when I initialized nytCount to 0, but then of course its value could only go up to 1 before it would be reinitialized on the next runthrough of the code.

Zhankfor
  • 121
  • 1
  • 8

2 Answers2

1

Well the main problem I see is that the chrome.storage.local.get call is asynchronous and has a required callback. Try changing it to something like this:

var nytCount = 0;
chrome.storage.local.get("nyt", function(items) {
    doStuff(items.nyt);
   // items.nyt is the value you want out of this
});

function doStuff(nyt){
  nytCount = nyt;
  if(nytCount == undefined)
    nytCount = 0;
  //put the rest of your code in here
  //so that it all runs after you get the number out of storage
}

Don't forget to update the value you have in storage with a chrome.storage.local.set call. For that one the callback is optional.

Rob W
  • 341,306
  • 83
  • 791
  • 678
BeardFist
  • 8,031
  • 3
  • 35
  • 40
1

chrome.tabs.query should only be used if you want to immediately query the state of the tabs.

To monitor how often you've visited a site, use one of the chrome.tabs events, such as chrome.tabs.onUpdated. To avoid double-counting, you should check if the changeInfo.status property is "complete".

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    var url = changeInfo.url; // String or undefined
    if (changeInfo.status == 'complete' && url && url.indexOf("nytimes.com") !== -1) {
        // TODO: increase counter by one
    }
});

Your next issue is the way how chrome.storage is used. It's an asynchronous API, so you cannot use a getter to read the actual value. Furthermore, the values will not magically saved back in the storage after reading.

For storing counters, I recommend localStorage over chrome.storage. It's a synchronous API, and well-suited for storing a small amount of data (such as counters). Only strings can be stored, so make sure that you cast the value to a number after reading:

var nytCount = +localStorage.getItem('nyt') || 0;

// Whenever you want to increase the counter:
localStorage.setItem('nyt', ++nytCount);

This assumes that only one page is interacting with the nyt variable. When the variable is used (read/write) by multiple pages (e.g. options + background page), you cannot rely on a local variable, and have to read the latest value before writing:

localStorage.setItem('nyt', (+localStorage.getItem('nyt') || 0) + 1);

If you want to take the asynchronous route (chrome.storage), you can either read the value on load (and defer/queue the chrome.tabs.onUpdated events), or always read+write the counter on update:

chrome.storage.local.get('nyt', function(items) {
    var nyt = items.nyt || 0;
    chrome.storage.local.set({
        nyt: nyt + 1
    }, function() {
        // Only here, you can be certain that the value has been saved
        // Usually less than one millisecond
    });
});
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • Thanks, Rob - you're very helpful! What does the '+' mean in "var nytCount = +localStorage.getItem('nyt') || 0;"? – Zhankfor Feb 28 '13 at 18:29
  • 1
    @Zhankfor It "casts" the value to a number. `localStorage.getItem('nyt')` could return `null`. +0 would return 0. It could also contain an invalid value, say a string. In that case, the unary `+` operator would return `NaN`. Both `0` and `NaN` are falsey, so when the OR operator kicks in, the righthand expression is evaluated, which is 0. The final result is that valid strings are converted to numbers, and invalid numbers are replaced with zero. – Rob W Feb 28 '13 at 18:32
  • Thanks again. I've used your code, but the debugger still doesn't seem to want to step into the curly braces after "chrome.storage.local.get('nyt', function(items)". It looks like this now: `var nytCount = +localStorage.getItem('nyt') || 0; console.log(nytCount); chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { var url = changeInfo.url; // String or undefined if (changeInfo.status == 'complete' && url && url.indexOf("NYTimes.com") !== -1) { localStorage.setItem('nyt', ++nytCount); }` (Sorry it's so messy.) – Zhankfor Feb 28 '13 at 18:44
  • @Zhankfor I don't see any `debugger;` statement in your code. If you set a breakpoint, make sure that it's set on the line containing `var url = changeInfo.url;`. If you put a breakpoint before it, the callback will be missed ([here is an analogy](http://stackoverflow.com/a/11689804) to help you understand why). PS. And use "nytimes.com" instead of "NYTimes.com". – Rob W Feb 28 '13 at 20:42