0

I'm having trouble figuring out how to use Chrome extension code asynchronously. The docs say that

Most methods in the chrome.* APIs are asynchronous: they return immediately, without waiting for the operation to finish. If you need to know the outcome of that operation, then you pass a callback function into the method. That callback is executed later (potentially much later), sometime after the method returns.

The documentation on executeScript seems to suggest that it is asynchronous, since it takes a callback that is called "after all the JavaScript has been executed".

Despite realizing all this, I'm having trouble figuring out how to use the script execution to my advantage.

Here's what I have in example.js:

var firstWords = "data:text/csv";

document.addEventListener('DOMContentLoaded', function() {

  chrome.tabs.query({ currentWindow: true }, function(tabs) {

    tabs.forEach(function(tab) {
      chrome.tabs.executeScript(tab.id, { file: "getFirstWord.js" }, function(result) {
        console.log("result of executeScript: ", result);

        firstWord = result[0];
        firstWords += firstWord;

        console.log("firstWords: ", firstWords)
      });

      console.log("AFTER EXECUTESCRIPT firstWords: ", firstWords)
    });

    console.log("AFTER FOREACH firstWords: ", firstWords)
  });

  console.log("AFTER QUERY firstWords: ", firstWords)
});

console.log("AFTER EVERYTHING firstWords: ", firstWords)

and in getFirstWord.js:

console.log("hello from getFirstWord.js");
document.title.match(/\w*/)[0]

Somewhat unsurprisingly, the output is not what I wish:

AFTER EVERYTHING firstWords:  data:text/csv
AFTER QUERY firstWords:  data:text/csv
AFTER EXECUTESCRIPT firstWords:  data:text/csv
AFTER EXECUTESCRIPT firstWords:  data:text/csv
AFTER EXECUTESCRIPT firstWords:  data:text/csv
AFTER FOREACH firstWords:  data:text/csv
result of executeScript:  ["Asynchronous"]
firstWords:  data:text/csvAnsynchronous
result of executeScript:  ["Washington"]
firstWords:  data:text/csvAnsynchronousWashington
result of executeScript:  ["Chicago"]
firstWords:  data:text/csvAnsynchronousWashingtonChicago

The ultimate goal is to accumulate a string of all the desired data (and convert to CSV).

Is there some kind of .done type of method, or some other way to use the call back, so that I can actually use the accumulated result once my query has finished?

Jay Quigley
  • 133
  • 1
  • 2
  • 6
  • 1
    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) – Makyen Feb 07 '17 at 12:57
  • 1
    Related: [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](//stackoverflow.com/q/23667086) – Makyen Feb 07 '17 at 12:58
  • 2
    While the APIs you are using are Chrome extension specific, there is nothing special about how these asynchronous functions work. They work just like most other asynchronous functions. There are a variety of semantics which may help with how you approach this, or how you conceptualize asynchronous functions. However, if you want to write code that does any of a significant variety of functions and situations (e.g. GUI interactions, real-world interfaces, multiprocessing...) and in many different computer languages, you are going to need to be able to understand how asynchronous functions work. – Makyen Feb 07 '17 at 13:06
  • @Mayken I feel more scolded than helped. – Jay Quigley Feb 07 '17 at 16:23
  • I got it working when surrounding some of my `console.log`s with a `setTimeout`, but I doubt that's optimal. I realize that using promises or callbacks can help me here, I'm just having trouble figuring out how to use either one. – Jay Quigley Feb 07 '17 at 16:24
  • 1
    `forEach` callback has an index parameter so simply check if it's the last one, in which case do what you need in executeScript's callback. Hint on chrome.* API: all methods that *may* accept a function callback as a parameter (see documentation for the full list) are asynchronous. – wOxxOm Feb 07 '17 at 18:32
  • 1
    I suggest using [promises](https://github.com/mozilla/webextension-polyfill) and [async/await](https://developers.google.com/web/fundamentals/getting-started/primers/async-functions) instead of callbacks, and [for(of)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) instead of forEach. – Daniel Herr Feb 07 '17 at 21:02

0 Answers0