0

I am very new to writing Firefox add-ons. But, I am trying my best. So, I have this code, which I got from MDN:

var tabs = require("sdk/tabs");

tabs.on('activate', function(tab) {
  var worker = tab.attach({
    contentScript: 'self.port.emit("html", document.body.innerHTML);'
  });
  worker.port.on("html", function(message) {
   console.log(message)
  })
});

When I change it to:

var contentHtml = '';

var tabs = require("sdk/tabs");

tabs.on('activate', function(tab) {
  var worker = tab.attach({
    contentScript: 'self.port.emit("html", document.body.innerHTML);'
  });
  worker.port.on("html", function(message) {
    contentHtml = message
  })
});

console.log(contentHtml);

It logs an empty string. Why is that?

What is the proper way of putting this into the variable contentHtml?

Makyen
  • 31,849
  • 12
  • 86
  • 121
Post Self
  • 1,471
  • 2
  • 14
  • 34
  • While the context of this question is using `port.on` in a Firefox add-on, it is effectively a duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) and [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 Mar 21 '16 at 23:56

1 Answers1

1

For more detailed discussion about asynchronous code in JavaScript see:

It logs an empty string. Why is that?

Because you set contentHtml = '';. At the time that you console.log(contentHtml);, it has not changed.

What is the proper way of putting this into the variable contentHtml?

The way you are doing it assigns it into contentHtml just fine.

Your issue is not functionally how to assign a value to contentHtml. It is not an issue specific to writing a Firefox add-on. Your issue is understanding the flow of asynchronous programming.

JavaScript tends to be written with unnamed functions defined inline where they are used. While this is more compact, I find that it tends to result in newer programmers not as readily understanding the execution flow of a program that is asynchronous.

I have re-written your code so it is more clear as to what happens when:

var tabs = require("sdk/tabs");
var contentHtml = '';

function workerAttachedToTabWhenTabActivated() {
    //This is executed every time a tab is activated.
    //It is not executed until that time.
    self.port.emit("html", document.body.innerHTML);
}

function receiveHtmlMessageFromWorkerViaPortOn(message) {
    //This is executed only when we receive a message via port.on that is named "html".
    //It is not executed until such a message is received.

    //We set contentHtml to message here. While the contentHtml variable is defined in the
    //  containing code, setting it here does not, currently, do us any good because
    //  the rest of the program has already completed by the time this is executed.
    contentHtml = message;

    //Show that we actualy do set contentHtml.
    console.log("contentHtml after receiving html message:" + contentHtml);
}

tabs.on('activate', function(tab) {
  var worker = tab.attach({
    contentScript: 'workerAttachedToTabWhenTabActivated();'
  });
  worker.port.on("html", receiveHtmlMessageFromWorkerViaPortOn(message))
});

//When we execute the following statement contentHtml is still "".
//When we get here, we have set up our functions that are executed upon a tab becoming
//active, but that code has not yet been executed because no tab became active in the small
//amount of time between setting up those listeners and this executing.
console.log("contentHtml after setting up tab.attach:" + contentHtml);

As you should be able to see, setting the global variable contentHtml to the message does not do much good in this instance because execution has already passed the statement

console.log("contentHtml after setting up tab.attach:" + contentHtml);

by the time contentHtml is set to the message. Setting the global variable contentHtml to the message would only do some good if there were other asynchronous code which might execute later in which it was desired to know what the most recent html message that had been received was.

In general, everything that depends on the contents of the html message should be put in the function that is executed when that message is received.

Community
  • 1
  • 1
Makyen
  • 31,849
  • 12
  • 86
  • 121