25

I'm creating (learning) an extension for Google Chrome.

To debug some code, I inserted console.log(), as follows:

var fourmTabs = new Array();
chrome.tabs.query({}, function (tabs) {
    for (var i = 0; i < tabs.length; i++) {
        fourmTabs[i] = tabs[i];
    }
});
for (var i = 0; i < fourmTabs.length; i++) {
    if (fourmTabs[i] != null)
        window.console.log(fourmTabs[i].url);
    else {
        window.console.log("??" + i);
    }
}

It's very simple code: get all tabs info into an array of my own, and print some things.

To check whether the code works as it should, I run the code. Here comes the problem:

  • When I use breakpoints (via the Developer tools), the code runs fine.
  • Without breakpoints, nothing is printed.

Any idea why?

Rob W
  • 341,306
  • 83
  • 791
  • 678
samy
  • 1,949
  • 6
  • 39
  • 64
  • thanks for the links, i understand the problem but im not sure how to fix it. can u give some ideas? or mybee some sample code on how will u do it? – samy Jul 27 '12 at 13:23
  • The key is "Properly rewrite your code, to correctly implement the **asynchronous** aspect" (quoted [my answer](http://stackoverflow.com/a/10955980)). What part do you not understand? Do you know the difference between synchronous and asynchronous programming? – Rob W Jul 27 '12 at 13:37
  • im still learning javascript and i guess i didnt got to this part yet. can u give me some refrences, or a simple code in the chrome extenstion area? – samy Jul 27 '12 at 13:43
  • **What** do you want to know? Do you know the [meaning of asynchronous and synchronous](http://stackoverflow.com/questions/748175/asynchronous-vs-synchronous-execution-what-does-it-really-mean)? Are you failing to see how your code relates to the async problem? If you ask a question, please include relevant details. Guessing is not very productive. – Rob W Jul 27 '12 at 13:46
  • sorry about that(silly me), i do want to unserstand how my code is failing. and how i solve the async problem. (thank for u the link) :) – samy Jul 27 '12 at 13:54
  • @RobW http://stackoverflow.com/q/23667086/2336725 is aiming to be a canonical reference for javascript asynchronicity. I'm not experienced enough on SO to know how that fact and this post should be integrated, if at all. – Teepeemm Apr 26 '15 at 01:43
  • 1
    @Teepeemm Putting a link to the other question (with context) (like you just did) is an effective way to let others know about the other question. I don't vote to close the question as a duplicate, because the answer below is less verbose and more to-the-point compared to the canonical answers. It may also be easier to relate the answer to other Chrome extension APIs because of the similar structure. (I've shared my thoughts about that canonical answer at http://meta.stackoverflow.com/a/255046) – Rob W Apr 26 '15 at 08:31

1 Answers1

103

Your problem can be simplified to:

/*1.*/ var fourmTabs = [];
/*2.*/ chrome.tabs.query({}, function(tabs) {
/*3.*/     fourmTabs[0] = tabs[0];
/*4.*/ });
/*5.*/ console.log(fourmTabs[0]);

You expect that the fourmTabs array is updated (by line 3) when line 5 is reached.
That is wrong, because the chrome.tabs.query method is asynchronous.


In an attempt to make you understand the significance of the asynchronous aspect, I show a code snippet with the same structure as your code and a story.

/*1.*/ var rope = null;
/*2.*/ requestRope(function(receivedRope) {
/*3.*/     rope = receivedRope;
/*4.*/ });
/*5.*/ grab(rope);
  • At line 1, the presence of a rope is announced.
  • At lines 2-4, a callback function is created, which ought to be called by the requestRope function.
  • At line 5, you're going to grab the rope via the grab function.

When requestRope is implemented synchronously, there's no problem:
  You: "Hi, I want a rope. Please throw the rope"call the callback function" when you've got one."
  She: "Sure." throws rope
  You: Jumps and grabs rope - You manage to get at the other side, alive.

When requestRope is implemented asynchronously, you may have a problem if you treat it as synchronous:
  You: "Please throw a rope at me."
  She: "Sure. Let's have a look..."
  You: Jumps and attempts to grab rope Because there's no rope, you fall and die.
  She: Throws rope Too late, of course.


Now you've seen the difference between an asynchronously and synchronously implemented function, let's solve your original question:

var fourmTabs = new Array();
chrome.tabs.query({}, function (tabs) {
    for (var i = 0; i < tabs.length; i++) {
        fourmTabs[i] = tabs[i];
    }
    // Moved code inside the callback handler
    for (var i = 0; i < fourmTabs.length; i++) {
        if (fourmTabs[i] != null)
           window.console.log(fourmTabs[i].url);
        else {
            window.console.log("??" + i);
        }
    }
});
// <moved code inside callback function of chrome.tabs.query>

With breakpoints, your code works, because by the time that the second part of the code is reached, the callback has already been called.

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 1
    wow! thank u!.now, i understand that i need to wait, befor getting the data into my arry. the rope example is great but, can u show me (if is not so hard) how will u make sure she will throw me the rope befor i jump into my death? – samy Jul 27 '12 at 14:37
  • 4
    @samy Simply jump *after* receiving the rope. The "jump logic" has to be appended to the callback function. I've added the code for your case at the end of the answer, I hope that you understand it now :) – Rob W Jul 27 '12 at 14:41
  • 2
    ohhhh, i see the diffrence now. now i understnad! thank u very much!! for taking the time and making me understand this topic :) – samy Jul 27 '12 at 14:44
  • 4
    one of the best answers on Stackoverflow. – doniyor Aug 10 '14 at 23:31
  • 3
    even 2 years latter that answer still is legend... wait for it ... ***dary*** – Dionys Oct 10 '14 at 07:56
  • How can asynchronous code like this be changed to be more DRY? Let's say this extension uses an array of open tabs in several places. What patterns should be used to make asynchronous code reusable? – GregB Nov 17 '14 at 15:12
  • 2
    @GregB Callbacks or promises. – Rob W Nov 17 '14 at 15:16
  • 1
    `grab(rope)` is definitely the best way to explain the difference between synchronous and asynchronous functions. Ingenious. – Marco Bonelli Jan 08 '15 at 01:49
  • 1
    Best analogy for synch vs asynch ever. – James Cushing Apr 02 '15 at 08:47