After Calling Chrome.Tabs.Query, the Results Are Not Available

After calling chrome.tabs.query, the results are not available

Your problem can be simplified to:

/*1.*/ var fourmTabs = [];
/*2.*/ chrome.tabs.query({}, function(tabs) {
/*3.*/ fourmTabs[0] = tabs[0];
/*4.*/ });
/*5.*/ console.log(fourmTabs[0]);

You expect that the fourmTabs array is updated (by line 3) when line 5 is reached.

That is wrong, because the chrome.tabs.query method is asynchronous.


In an attempt to make you understand the significance of the asynchronous aspect, I show a code snippet with the same structure as your code and a story.

/*1.*/ var rope = null;
/*2.*/ requestRope(function(receivedRope) {
/*3.*/ rope = receivedRope;
/*4.*/ });
/*5.*/ grab(rope);
  • At line 1, the presence of a rope is announced.
  • At lines 2-4, a callback function is created, which ought to be called by the requestRope function.
  • At line 5, you're going to grab the rope via the grab function.

When requestRope is implemented synchronously, there's no problem:

  You: "Hi, I want a rope. Please throw the rope"call the callback function" when you've got one."

  She: "Sure." throws rope
  You: Jumps and grabs rope - You manage to get at the other side, alive.

When requestRope is implemented asynchronously, you may have a problem if you treat it as synchronous:

  You: "Please throw a rope at me."

  She: "Sure. Let's have a look..."

  You: Jumps and attempts to grab rope Because there's no rope, you fall and die.

  She: Throws rope Too late, of course.


Now you've seen the difference between an asynchronously and synchronously implemented function, let's solve your original question:

var fourmTabs = new Array();
chrome.tabs.query({}, function (tabs) {
for (var i = 0; i < tabs.length; i++) {
fourmTabs[i] = tabs[i];
}
// Moved code inside the callback handler
for (var i = 0; i < fourmTabs.length; i++) {
if (fourmTabs[i] != null)
window.console.log(fourmTabs[i].url);
else {
window.console.log("??" + i);
}
}
});
// <moved code inside callback function of chrome.tabs.query>

With breakpoints, your code works, because by the time that the second part of the code is reached, the callback has already been called.

No result from chrome.tabs.query in Opera

It seems that Opera does not include the concept of a highlighted tab, which is already pretty obscure in Chrome.

Your query is excessive anyway: in Chrome, the active tab cannot be non-highlighted.

So, for a query that works in both, use {active: true, currentWindow: true}.

Putting chrome.tabs.query in a function always returns undefined

chrome.tabs.query is asynchronous, so your return executes before the theTab = tab in the callback or the callback itself is executed, So try:

function _getCurrentTab(callback){ //Take a callback
var theTab;
chrome.tabs.query({active:true, currentWindow:true},function(tab){
callback(tab); //call the callback with argument
});
};

_displayTab(tab){ //define your callback function
console.log(tab);
};

_getCurrentTab(_displayTab); //invoke the function with the callback function reference

Chrome extension: Execute some code if a specific tab is not found

You should use chrome.tabs.query() instead of chrome.tabs.getAllInWindow(). The .query method, if called with an empty queryInfo object, will find ALL the tabs.

So, your code should be like this:

chrome.tabs.query({}, function(tabs) {
var found = false;
for (var i=0; i < tabs.length; i++) {
if (/https?:\/\/www\.youtube\.com/.test(tabs[i].url)) {
found = true;
chrome.tabs.update(tabs[i].id, {url: 'https://www.youtube.com/watch?v=somevideid', active: true});
break; // you found it, stop searching and update the tab
}
}

if (!found) chrome.tabs.create({url: 'https://www.youtube.com/watch?v=somevideid', active: true});
// you didn't find it, create a new tab with the new url and select it
});

Also, I used the regexp /https?:\/\/www\.youtube\.com/ to test the url of the tab, because the url may begin with "http" or "https", or may have some query string attached, like "?hl=en" or similars, so using tab[i].url == "http://www.youtube.com/" will not provide you absolute certainty of finding the tab.

Chrome Extension: runtime.lastError while running tabs.get/tabs.remove: No tab with id:0

Xan has given you an excellent clue as to what is going on, but let me try to answer your question, because it especially relates to chrome extensions. Your callback function in getTabID runs asynchronously, meaning it doesn't block whatever other code may run. So, in closeBundle, you call getTabID, which starts to run, but closeBundle continues to run even before getTabID is finished running its callback. Therefore, tabID is still 0 when you call chrome.tabs.get, and you get an error. In short, the entire architecture of your code won't work, because of the asynchronous nature of JavaScript.

One readily available solution is to wrap everything in callback functions (frequently known as callback hell). I've built chrome extensions with 5 or 6 nested callback functions. One really needs to understand this asynchronous behavior to program and debug chrome extensions, and JavaScript in general. A quick Google search will give you endless articles on the subject. Xan's comment is a good place to start.

But for example in your code, some pseudo code might look something like this:

function getTabnumber(){
chrome.tabs.query({'currentWindow': true}, function(tabarray){
tabnumber = tabarray.length;
for(i=0;i<tabnumber;i++){
chrome.tabs.query({'currentWindow': true, 'active': true}, function(tabArray){
tabID = tabArray[0].id;
chrome.tabs.get(tabID , function(tab){ //here is the first problem
insert[i] = tab; //for saving all Tabs in an array
});
chrome.tabs.remove(tabID); //here the second one
}
});
});
}

This code isn't tested or meant to run, just to give you an idea of what I mean by nested callbacks. Hope this helps, good luck.



Related Topics



Leave a reply



Submit