0

I'm writing a Chrome extension for my own use. I'm querying the current tab's index from an injected script like this:

[injected script]

chrome.runtime.sendMessage({whatIsMyIndex:1}, function(response){
   var myIndex = response.index;
});

[background script]

chrome.runtime.onMessage.addListener(
   function(request, sender, sendResponse) {
      if (request.whatIsMyIndex){
         sendResponse({index: sender.tab.index});
      }
   }
);

Now this is all good and fine, but then I need to return the url of the first tab as well:

[injected script 2]

chrome.runtime.sendMessage({whatIsMyIndex:1}, function(response){
   var myIndex = response.index;
   var url = response.url;
});

[background script 2]

var url;

//this uses sendResponse when the requested values arrive
function respond(sendResponse, index){
   if(typeof(url)!="undefined"){
      sendResponse({index:index, url:url});
   } else {
      setTimeout(respond, 15, sendResponse, index);
   }
}

chrome.runtime.onMessage.addListener(
   function(request, sender, sendResponse) {
      if (request.whatIsMyIndex){
         chrome.tabs.query({index:0, currentWindow:true}, function(tabs){
            url=tabs[0].url;
         }
         setTimeout(respond, 15, sendResponse, sender.tab.index);
         return true; //so i can use sendResponse later
      }
   }
);

Now, this code works just fine. My question is, is there any way to accomplish this without the need for setTimeout? Adding a fixed 15ms delay doesn't seem right.

If only I could get chrome.tabs.query's callback to take my sendResponse() as a parameter...

(Storing sendResponse() in a global variable is not possible, since there will be ~20 tabs doing this at the same time, and all of them need their own responses.)

I don't need any working (or not working) code here, only some ideas/guidelines.

proto-n
  • 545
  • 6
  • 19

1 Answers1

8

Just call sendResponse inside the chrome.tabs.query callback, instead of setting the variables:

chrome.runtime.onMessage.addListener(
   function(request, sender, sendResponse) {
      if (request.whatIsMyIndex){
         chrome.tabs.query({index:0, currentWindow:true}, function(tabs){
            sendResponse({index:sender.tab.index, url:tabs[0].url});
         });
         return true; //so i can use sendResponse later
      }
   }
);

Each invocation of the onMessage callback function creates a new closure, so the sendResponse inside the tabs.query callback function will be bound to the right function.

Rob W
  • 341,306
  • 83
  • 791
  • 678
rsanchez
  • 14,467
  • 1
  • 35
  • 46
  • Awesome, saved hours of trying to figure that one out, but why does the `return true` help make this work?! – r0bb077 Apr 22 '15 at 11:32
  • @rsanchez Thank you, I could solve my problem with this too. and I just wonder, why it is not working without 'return true;'?. This was my problem, and I still don't understand how it works. I thought once we return something, the connection between background and popup will be done... please advise, – Expert wanna be Jun 18 '15 at 08:21