23

Sometimes there is tab Id stored in a variable and you need to check if tab still exists before doing something with it (because users can close tabs at any time). I've found this solution:

chrome.tabs.get(1234567, function(tab) {
  if (typeof tab == 'undefined') {
    console.log('Tab does not exist!');
  }
});

It works but it has quite serious disadvantage. It writes error message into console like this:

Error during tabs.get: No tab with id: 1234567.

And this is not an exception. So try/catch can't help. It's just a message in console.

Any ideas?

UPDATE: This error now looks like

Unchecked runtime.lastError while running tabs.get: No tab with id: 1234567.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Konstantin Smolyanin
  • 17,579
  • 12
  • 56
  • 56
  • Why not look through the result of `chrome.windows.getAll` instead? – Ian May 15 '13 at 17:32
  • 2
    Instead of checking if it exists, why not explicitly remove that particular `tabId` when the tab is closed. Just listen to the `onRemoved` event. – BeardFist May 15 '13 at 18:32
  • Yes it's possible to implement the solution using `onRemoved` but it will not be the simplest. You will need to store the array of IDs somewhere. Where? In background page? So you will need to send messages to background page to know if tab still exists. And you will need to not forget to put IDs of all opened tabs into this array. It's quite cumbersome solution, isn't it? – Konstantin Smolyanin May 16 '13 at 12:44
  • 1
    The message is not showing in the console anymore. `Chrome Version 39.0.2171.65 m` – Jo E. Nov 24 '14 at 15:18
  • @KonstantinSmolyanin The edit to your question is misleading, the error itself can still appear. I suggest to accept anglinb's answer, because that is correct. – Rob W Jan 23 '15 at 22:48
  • @Rob W ... interesting ... why do you think that it can appear once again in future releases of Chrome? Since Chrome 39 as Deadpool says it has disappeared (I've tested it in Chrome 40 and confirm that it has disappeared). But you have impolitely edited may addition to the question where I've said about this. And BTW I can't accept anglinb's answer now because this error doesn't appear any more independently check you chrome.runtime.lastError or not. – Konstantin Smolyanin Jan 24 '15 at 11:46
  • @KonstantinSmolyanin The error never disappeared in the first place. See http://i.stack.imgur.com/S0U7z.png (40.0.2214.91, also tested in 39.0.2171.96). If that screenshot doesn't convince you, I invite you to read Chromium's source code: https://cs.chromium.org/%22TabsGetFunction::RunSync()%22. – Rob W Jan 24 '15 at 11:53
  • 1
    @RobW hmmm ... yesterday I've checked it but ... ok, I'm sorry. And anglinb is completely right about chrome.runtime.lastError. – Konstantin Smolyanin Jan 24 '15 at 12:03

5 Answers5

28
function callback() {
    if (chrome.runtime.lastError) {
        console.log(chrome.runtime.lastError.message);
    } else {
        // Tab exists
    }
}
chrome.tabs.get(1234,callback);

source Chrome Extension error: "Unchecked runtime.lastError while running browserAction.setIcon: No tab with id"

Edit:

Chrome checks if the value of chrome.runtime.lastError was checked in a callback, and outputs a console message for this "unhandled async exception". If you do check it, it won't pollute the console.

From the comment by @Xan

Community
  • 1
  • 1
anglinb
  • 975
  • 1
  • 8
  • 15
  • 1
    As far as I can tell, the idea here is that Chrome checks if the value of `chrome.runtime.lastError` was checked in a callback, and outputs a console message for this "unhandled async exception". If you do check it, it won't pollute the console. – Xan Dec 18 '14 at 10:04
  • That's exactly right. I will add that to the answer. – anglinb Dec 18 '14 at 18:34
  • After implementing this fix, sometime I receive "Unchecked runtime.lastError while running tabs.executeScript: The tab was closed." error in background console. Any idea? – webcoder Mar 05 '15 at 12:10
  • Note that this works in most cases (including for the question posed here), but not every case. I've received an invalid tab id error in the background page for `chrome.browserAction.setBadgeText()` before. – thdoan Apr 17 '18 at 21:55
4

There is another solution based on Ian's comment (thank you @Ian) to the question.

function tabExists (tabId, onExists, onNotExists) {
  chrome.windows.getAll({ populate: true }, function (windows) {
    for (var i = 0, window; window = windows[i]; i++) {
      for (var j = 0, tab; tab = window.tabs[j]; j++) {
        if (tab.id == tabId) {
          onExists && onExists(tab);
          return;
        }
      }
    }
    onNotExists && onNotExists();
  });
}

It is tested and works good so everybody can use it. If somebody can find shorter solution then using chrome.windows.getAll please write!

UPDATE: Since @anglinb's answer this my answer is not actual any more

Konstantin Smolyanin
  • 17,579
  • 12
  • 56
  • 56
  • 3
    This method is more heavy than a simple `chrome.tabs.get`. If you need to call the method very often, I recommend against the method. If you really hate the original error message, override the `console.error` method to get rid of it. Or use `console.clear();` to wipe the console. – Rob W Sep 15 '13 at 20:01
  • Override `console.error` just to get rid of single message? This is a joke, I think. – Konstantin Smolyanin Sep 15 '13 at 21:44
  • 1
    No, I'm not kidding. You can override the `console.error` method, filter the message and call the original `console.error` method if wanted. This is less expensive than your current method. – Rob W Sep 15 '13 at 21:50
  • 2
    Update to my comment above: You cannot override the `console` used by the internal extension runtime any more. – Rob W Jan 23 '15 at 22:49
  • @RobW, Why not? What's the solution then to override the global error handler? It's required to solve the problem at https://stackoverflow.com/questions/32131089/unable-to-check-runtime-lasterror-during-browseraction-setbadgetext#comment78167391_32131089 – Pacerier Aug 10 '17 at 04:11
2

I'm quite surprised that there's no API to do this simple task. Apart from what @KonstantinSmolyanin suggested above, I came up with this simpler method:

function checkTabIDValid(nTabID, callbackDone)
{
    chrome.browserAction.getBadgeText({tabId: nTabID}, function(dummy)
    {
        if(callbackDone)
            callbackDone(!chrome.runtime.lastError);
    });
}

Unfortunately it also has to report result asynchronously:

checkTabIDValid(tabId, function(res){
    console.log("tab " + (res ? "exists" : "doesn't exist"));
});
c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • I didn't check it yet but it looks a bit better than my solution. – Konstantin Smolyanin Oct 03 '14 at 16:43
  • @KonstantinSmolyanin: So where you able to check? I'm not trying to outdo you, I just want to find a faster solution than enumerating through all the tabs. – c00000fd Oct 08 '14 at 20:25
  • 1
    @c00000fd, getBadgeText is not the only way, I bet there are tons others (eg executeScript). But quite frankly, these workarounds are ugly and pointless since there is `chrome.tabs.get(1234,callback);` – Pacerier Aug 10 '17 at 04:15
2

Indeed, there is no "exists" function in chrome API... I've written this code:

  var tabID = 551;
  chrome.tabs.query(  {}, function(tabs) {
    for(let i = 0; i<tabs.length; i++){
      if (tabs[i].id === tabID) {
        alert(`Tab ${tabID} exists!`);
        return;
      }
    }
    alert(`No Tab ${tabID} here.`);
  });
Max Kur
  • 46
  • 4
-2

Set a variable before

lastRemoved=tab.id;
chrome.tabs.remove(tab.id);

And check it after

chrome.tabs.onUpdated.addListener(function(tabId){
    if(lastRemoved==tabId) return;
    chrome.tabs.get(tabId,
    //...
holden321
  • 1,166
  • 2
  • 17
  • 32