1

Ich bin sehr neu beim Schreiben von Firefox Add-ons. Aber ich versuche mein Bestes. Also, ich habe diesen Code, den ich got from MDN:Warum wird eine globale Variable nicht sofort nach dem Definieren einer Callback/Listener-Funktion gesetzt (asynchrones Messaging, port.on)

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) 
    }) 
}); 

Wenn ich es ändern:

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); 

Es protokolliert eine leere Zeichenfolge. Warum das?

Was ist der richtige Weg, dies in die Variable contentHtml zu setzen?

+0

Während der Kontext dieser Frage 'port.on' in einem Firefox Add-On verwendet, ist es effektiv ein Duplikat von [Warum ist meine Variable unverändert, nachdem ich sie in einer Funktion geändert habe? - Asynchrone Code-Referenz] (http://stackoverflow.com/questions/23667086/why-is-my-variable-unterned-after-i-modify-it-inside-of-a-function-asynchron) und [How do Ich gebe die Antwort von einem asynchronen Anruf zurück?] (Http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call). – Makyen

Antwort

1

Für detailliertere Diskussion über asynchronen Code in JavaScript sehen:

Es protokolliert eine leere Zeichenfolge. Warum das?

Weil Sie contentHtml = ''; setzen. Zu der Zeit, dass Sie console.log(contentHtml); haben, hat es sich nicht geändert.

Was ist der richtige Weg, dies in die Variable contentHtml zu setzen?

Die Art, wie Sie es tun, ordnet es in contentHtml ganz gut.

Ihr Problem ist nicht funktional, wie Sie einen Wert contentHtml zuweisen. Es ist kein spezifisches Problem, ein Firefox Add-on zu schreiben. Ihr Problem besteht darin, den Ablauf der asynchronen Programmierung zu verstehen.

JavaScript wird normalerweise mit unbenannten Funktionen geschrieben, die inline definiert sind, wo sie verwendet werden. Obwohl dies kompakter ist, stelle ich fest, dass es tendenziell dazu führt, dass neuere Programmierer den Ausführungsfluss eines Programms, das asynchron ist, nicht so leicht verstehen.

Ich habe Ihren Code neu geschrieben, so dass es mehr klar, ist das, was passiert, wenn:

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); 

Wie Sie sollen sehen können, die globale Variable Einstellung contentHtml auf die message nicht viel Gutes tun in diesem Fall, da die Ausführung der Anweisung bereits vergangen

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

durch die Zeit hat contentHtml zum message gesetzt. Das Setzen der globalen Variable contentHtml auf message würde nur dann etwas nützen, wenn es einen anderen asynchronen Code gäbe, der später ausgeführt werden könnte, wo man wissen wollte, was das zuletzt empfangene htmlmessage war.

Im Allgemeinen sollte alles, was vom Inhalt des htmlmessage abhängt, in die Funktion gestellt werden, die ausgeführt wird, wenn diese Nachricht empfangen wird.

Verwandte Themen