9

I know that waiting for an asynchronous method is stupid, one should use callbacks instead. But what if an third party API forces you to be synchronous?

I'm developing a Chrome Extension that will prevent the user from visiting websites that's already open in another tab. I basically need to cancel requests based on the urls in open tabs. I want to use chrome.webRequest.onBeforeRequest like this:

function onBeforeRequest(details) {
  var websiteAlreadyOpenInOtherTab;

  // Here i want to set `websiteAlreadyOpenInOtherTab` by using the `chrome.tabs`
  // API. It's asynchronous though and that's my problem. I cant return a value
  // from an asynchronous method call.

  if (websiteAlreadyOpenInOtherTab) {
    return { cancel: true };
  }
}

chrome.webRequest.onBeforeRequest.addListener(
  onBeforeRequest,
  { urls: ['<all_urls>'], types: ['main_frame'] },
  ['blocking']);

Hopefully you see my dilemma in the code above. I need to return an object based on the result of asynchronous method calls. Is it possible to achieve this?

4
  • Can't you listen to all chrome.tabs changes and have websiteAlreadyOpenInOtherTab already containing the right value when onBeforeRequest is called? Commented Feb 28, 2013 at 0:12
  • I think you're approaching the problem incorrectly. Firstly, if things need to be asynchronous, then instead of requiring a synchronous response, work within the model and use an asynchronous callback in which if you decide the tab shouldn't be open, you close it. There is a separate API function to close tabs, you don't need to return false just from the onbeforerequest... Commented Feb 28, 2013 at 0:23
  • @davin: But that'll lead to "tab flickering" or something, a completely different behaviour (and a request would be sent) Commented Feb 28, 2013 at 0:46
  • @Bergi Yeah, almost. onBeforeRequest can't contain the right value (because I won't know it before onBeforeRequest is called. But I could maintain some kind of structure that knows about open tabs. It's a walk-around alright. @davin +1 on @Bergi's arguments. It's unacceptable to send a request and close the tab in my use case. The request should be canceled. But thanks for your suggestion anyway. :) Commented Feb 28, 2013 at 5:54

1 Answer 1

6

Maybe you can solve the problem by keeping track of the tab URLs?:

  1. When the app starts, get all open tab URLs by using chrome.tabs.query
  2. Subscribe to chrome.tabs.onUpdated and chrome.tabs.onRemoved and add/remove/update the URLs when they change.

Some kind of code example based on the documentation:

var tabUrlHandler = (function() {
   // All opened urls
   var urls = {},

   queryTabsCallback = function(allTabs) {
      allTabs && allTabs.forEach(function(tab) {
          urls[tab.id] = tab.url;
      });
   },

   updateTabCallback = function(tabId, changeinfo, tab) {
       urls[tabId] = tab.url;
   },

   removeTabCallback = function(tabId, removeinfo) {
       delete urls[tabId]; 
   };

   // init
   chrome.tabs.query({ active: true }, queryTabsCallback);
   chrome.tabs.onUpdated.addListener(updateTabCallback);
   chrome.tabs.onRemoved.addListener(removeTabCallback);

   return {
     contains: function(url) {
        for (var urlId in urls) {
           if (urls[urlId] == url) {
              return true;
           }
        }

        return false;
     }
   };

}());

Now you should be able to ask the tabUrlHandler directly in your onBeforeRequestMethod:

function onBeforeRequest(details) {
  var websiteAlreadyOpenInOtherTab = tabUrlHandler.contains(details.url);

  if (websiteAlreadyOpenInOtherTab) {
    return { cancel: true };
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Awesome! Thanks for a very detailed example, this is the route I have to take.
Thanks! +1 for an interesting question! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.