0

In a Chrome App, I have a webview that uses an onHeadersReceived handler to redirect certain requests to a data URI constructed on the fly. The data URI depends on data from a remote script that manipulates contents from the original URL.

function getDataUri(myurl, callback) {
    var url = "http://some.where/myscript?url=" + myurl;
    $.getJSON(url, function(data){
       var dataUri = "data:application/json;charset=utf-8;base64," 
                     + btoa(JSON.stringify(data));
       callback(dataUri);
    })
}
 
webview.request.onHeadersReceived.addListener(
  function(info) {
      var myDataUri;
      getDataUri(info.url, function(dataUri) {
         myDataUri = dataUri;
         console.log("Here is my data uri:", dataUri);
      })
      return {redirectUrl: myDataUri}; // This won't work!
  }, 
  {urls: ["*://example.com/*"]}, ["blocking"]
);

//Calling it directly works fine:
var url = "http://example.com/some/path";
getDataUri(url, function(dataUri){
   console.log("Here is my data uri:", dataUri);
})

A synchronous AJAX request would be an easy workaround, but this is not allowed in Chrome apps.

The example uses jQuery $.getJSON, but that is not important. It could be a plain XHR request instead.

I am fully aware of the asynchronous nature of JavaScript and use it extensively throughout the 2800 lines of code. But, in this case, I need to chain the getDataUri() function from a webrequest event handler and I can't figure out how this is done. And, if it is possible at all.

To expand a bit more on the problem:

The real problem is that the event listener can't return until the data URI is ready. Since we can't pass on a promise or a callback, we will somehow have to wait for dataUri to be populated. This implies some form of synchronous mode which is why it is perhaps not possible at all.

If this wasn't going on in an event handler, I could simply pass the callback on all the way from the first level.

Community
  • 1
  • 1
marlar
  • 3,858
  • 6
  • 37
  • 60
  • Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Andreas Feb 18 '17 at 14:04
  • Is this in `content_script` file? and post your manifest.json, i think the js file parsed before DOM loaded. – nivas Feb 18 '17 at 14:12
  • What do you mean by "achieve"? Is it possible for an async request to immediately return the value it is fetching? No. Is it possible to do whatever you are trying to do in an async way? Yes. In an async callback, you want to do something with the data you receive, not return it. Call whatever function is going to actually use `{redirectUrl: datauri}`. – Damon Feb 18 '17 at 14:14
  • change that black to `return $.getJSON(url, function(data){ var dataUri = "URL here"; return dataUri; })` – nivas Feb 18 '17 at 14:22
  • @nivas: it's not in content_script. This is a Chrome packaged app and the file is the main.js file. Content scripts are for Chrome Extensions. – marlar Feb 18 '17 at 14:23
  • I know and understand its an app, have you tried above method? and add a `console.log(datauri);` in addListener function, if you want to return the value you have to create certain `timeOut` for it – nivas Feb 18 '17 at 14:25
  • @Damon: I have expanded and rephrased the question to make it more clear. – marlar Feb 18 '17 at 14:39
  • @Andreas: it's not a duplicate. I have expanded the question to show the difference. – marlar Feb 18 '17 at 15:20
  • It still is... Did you read the accepted answer and the link at the top of it? – Andreas Feb 18 '17 at 15:24
  • Yes, I did. The accepted answer is more a list of possible solutions to a general question of how to deal with the asynchronous nature of JS. And the link at the top explains why you just can't get a variable value right away after calling an asynchronous function. In my case the specific problem is how to return the value obtained from the ajax response to the event handler. Note the last example of calling getDataUri directly and logging the value to the console. That is easy. I have thought of promises, but I can't figure out if that could be used here. I think not. – marlar Feb 18 '17 at 15:50
  • @nivas: Using the result from $.getJSON doesn't work because it returns immediately before there response body is ready. – marlar Feb 18 '17 at 18:44
  • The thing you want to do won't work because a blocking webRequest is synchronous whereas ajax is not. And if you force ajax to be synchronous you can say goodbye to fast browsing. – wOxxOm Feb 18 '17 at 22:56
  • However, you can try sending ajax in onBeforeRequest, save the response in a hashtable-like object that will be checked in onHeadersReceived in a *hope* that your ajax completes faster than headers are received. Or you can send the ajax when the user only hovers a link even before clicking it. – wOxxOm Feb 18 '17 at 23:14
  • @wOxxOm: I fully agree with your comment about forcing ajax to be synchronous. However, this is a controlled environment where the event handler will only run on a certain page, and only once for each page load. I think you're on the right track with preparing the response in advance. Doing it in onBeforeRequest will probably not work (not enough time) but I can force a page reload and thus have the response ready in the second run. Again, this is a controlled situation and the page reload won't be a problem in the specific use case. – marlar Feb 19 '17 at 09:16

0 Answers0