I'm developing a google plugin/extension and I came across a problem where I can only speculate about its cause. In my background.js background script I'm attempting to send image data to my content.js content script.
When I load the page in a new tab for the first time I'm only getting "response sent!", but no "response received". Then I refresh with the f5 key and this time I get the awaited "response received" message as well.
Is it possible that my background.js simply isn't in memory yet? And if so, how do I fix that? It also happens when I reload my plugin under chrome://extensions/ and reload an already existing tab.
background.js
chrome.extension.onMessage.addListener(
function(msg, sender, sendResponse) {
if((msg.action && (msg.action == "getPixels")) && msg.imgPath)
{
var canvas = document.createElement("canvas");
canvas.style.border = "none";
var img = new Image();
img.src = msg.imgPath;
var thewaitx = function()
{
if(img.complete && (img.width + img.height) > 0)
{
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0);
data = canvas.getContext("2d").getImageData(0, 0, img.width, img.height).data
sendResponse({value: data});
alert("response sent!");
}
else {setTimeout(thewaitx, 2000);}
};
thewaitx();
}
}
);
content.js
function findDataBySignature()
{
img = document.getElementsByClassName("someid")[0].getElementsByTagName("img")[0];
chrome.extension.sendMessage({action: "getPixels", imgPath:img.src}, function(response)
{
alert("response received");
data = response.value;
//blahblah
}
}
Sorry for linking to the wrong problem at first.
In your code, you're requesting an image, and depending on whether it is already loaded you're either doing something to it or use setTimout
to wait.
Your code works the second time because the image is already loaded; the first time it is not, and the listener terminates without calling sendResponse
(setTimeout
is asynchronous).
Google documentation mentions that special care needs to be taken to let Chrome now you're going to call sendResponse
asynchronously (as opposed to simply no response):
This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until
sendResponse
is called).
So, to make it work, you need to return true;
from the branch where you're not going to call sendResponse
immediately.
That said, I have to comment on your code: you should not use setTimeout
to wait for image load. Use an event-based approach:
var img = new Image();
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0);
data = canvas.getContext("2d").getImageData(0, 0, img.width, img.height).data
sendResponse({value: data});
alert("response sent!");
};
img.src = msg.imgPath;
// Check if image is already loaded (required if from cache)
if(img.complete || img.readyState === 4) { img.onload(); }
else {
return true; // For asynchronous sendResponse() call
}