I've just started playing with Chrome extensions.
In my content.js I have following
chrome.runtime.sendMessage("", function(response){
//some logic
});
And in background.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
sendResponse(someFunction);
return true;
});
function someFunction(para) {
//logic
}
The issue is, the response in content.js is always undefined... The similar posts on this site is usually due to asynchronous calls such as ajax, but I'm not doing anything asynchronously and I'm returning true which according to the docs returns the method... I can only assume my logic is some how backwards?
What have I done wrong?
you cant send a function ("someFunction") as a response. the response object must be serializable.
Related
Migrating extension mv2 to mv3 version. There was a problem with sending messages from one background page to another.
There are two utils (background pages), in order to use the methods of the first in the second and the second in the first, do I need to send messages between these two background pages? or through the main service worker?
I send messages without a service-worker, directly from one utility to another.
chrome.runtime.sendMessage({ type: 'typeMessage' }, (res) => {
return res;
});
But in another utility the listener does not receive this message
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
const { type, payload } = message;
switch (type) {
case 'typeMessage':
// any code
return;
default:
return Promise.resolve(`Message received: ${type}`);
}
});
Please tell me what am I doing wrong?
Sending messages from jsx (foreground) to js (service-worker) works. But from js (background) to another js (background) no.
This question already has answers here:
chrome extension - sendResponse not waiting for async function [duplicate]
(1 answer)
chrome extension - how i can await for chrome.runtime function?
(1 answer)
Closed 12 months ago.
I'm playing around with Promises available in Chrome extensions Manifest V3, but I'm not getting the expected results. What I'm trying to achieve: store some data from a browser action popup, then get a response back after the data is saved. Here's what I have so far:
background.js (service worker)
async function handleMessage(message, sender, sendResponse) {
switch (message.request) {
case 'setTimestamp':
await chrome.storage.local.set(message.data);
sendResponse({
status: chrome.runtime.lastError ? 'error' : 'ok'
});
break;
default:
sendResponse(null);
}
}
chrome.runtime.onMessage.addListener(handleMessage);
popup.js
// Event handler for button in popup.html
async function setTimestamp() {
const response = await chrome.runtime.sendMessage({
request: 'setTimestamp',
data: {
timestamp: performance.now()
}
});
console.log('setTimestamp response', response);
}
The timestamp is being saved successfully, but the response in popup.html is undefined instead of {status: 'ok'} that I was expecting. Can someone please point out what I'm doing wrong?
(Note: I'm aware you can use storage.local.set() directly from the popup and validate that the data was saved successfully by detecting chrome.runtime.lastError in the callback, but I wanted to use the new aync/await pattern above.)
Following scenario:
I use Node.js to connect to an API.
I fire a request and get a jsonp response back.
This response look like:
processResponse({"LoginResponse":{"#token":"x"}})
That's it. Just that line: A string/object/text.
I have also a function processResponse()
processResponse(data){
console.log(data);
};
My Question: How to get that response executed, since it is just an object. I wish to 'parse' a string to a function call.
client.methods.loginRequest(loginArgs, function(data,response){
//response body as js object
console.log(data);
// processResponse({"LoginResponse":{"#token":"x"}})
// now I wish to execute it.
data; // this doesn't work
data.exec(); // this doesn't work
? // what else
});
function processResponse(data){
console.log(data);
};
I hope there is a way?
I started using zombiejs, but i have some begginer questions:
1.) How testing ajax calls ?
For example i have php ajax action (Zend)
public function ajaxSomeAction()
{
$oRequest = $this->getRequest();
if($oRequest->isXmlHttpRequest() === false || $oRequest->isPost() === false) {
throw new Zend_Controller_Action_Exception('Only AJAX & POST request accepted', 400);
}
//process check params...
}
My zombiejs testing code throws http 400.
2.) How fire jquery plugins public methods ? For example i have code:
(function($) {
$.manager.addInvitation = function()
{
//some code ....
}
$.manager = function(options)
{
//some code
}
})(jQuery);
I try:
Browser.visit(url, function(err, browser, status)
{
// not work
browser.window.jQuery.manager.addInviation();
// also not work
browser.document.jQuery.manager.addInvitation();
browser.window.$.manager.addInvitation();
browser.evaluate('$.manager.addInvitation();');
})
3.) How modifiy header with zombiejs ? For exmaple i want add header x-performace-bot:zombie1 to request send using visit method
Browser = require('zombie');
Browser.visit(url, {debug:true}, function(err, browser, status)
{
//send request witch header x-performace-bot
});
After quick testing (on zombie 0.4.21):
ad 1.
As you're checking ($oRequest->isXmlHttpRequest()) if request is an xml http request, you have to specify (in zombie) X-Requested-With header with a value of XMLHttpRequest.
ad 2.
// works for me (logs jQuery function - meaning it's there)
console.log( browser.window.jQuery );
// that works to...
browser.window.$
Your code must be undefined or there are some other errors in Javascript on your page.
ad 3.
There's a header option, which you can pass just as you do with debug.
Something strange happens in the Chrome extension.
Content script:
console.log('content');
chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
console.log('request received');
sendResponse();
});
chrome.extension.sendRequest( JSON.stringify({'msg': 'page_loaded'}) );
It is just listens for extension messaging and sends the message to the background when page loaded.
Background script:
console.log('bg');
chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
sendResponse();
chrome.tabs.sendRequest(
sender.tab.id,
JSON.stringify({'msg': 'page_loaded_bg_receive'}),
function(){
console.log('sendRequest page_loaded_bg_receive callback');
});
});
It is listens for messages and sends message to the sender tab.
And it seems to be working, at least in most cases in the page log appears 'request received'.
While url entering Chrome sometimes loads typed address before user hits 'enter'. And that's a strange behavior: page loading, content-script runs, sends the message to the background, but when the background sends the message back — it fails with the background log message:
Port error: Could not establish connection. Receiving end does not exist. miscellaneous_bindings:184
chromeHidden.Port.dispatchOnDisconnect miscellaneous_bindings:184
Is this a Chrome bug? What to do to send message to the preloading tab?
This is the arfificial minimal sample to reproduce such behavior. I need to call 'chrome.tabs.sendRequest' after the handling the message and more than once, so calling the 'sendResponse' is not the solution.
Solution based on the article https://developers.google.com/chrome/whitepapers/pagevisibility. I run content-script code if document.webkitVisibilityState is not 'hidden' or 'prerender', elsewhere I listen for 'webkitvisibilitychange' and wait for document.webkitVisibilityState is not 'hidden' or 'prerender'. I think check for 'prerender' is enough, but when I open a new empty tab it loads page with document.webkitVisibilityState='hidden' and this page also did not receive background messages.
function isDocumentReady() {
return document.webkitVisibilityState != "hidden" && document.webkitVisibilityState != "prerender";
}
if (isDocumentReady())
main();
else {
function onVisibilityChange() {
if (!isDocumentReady())
return;
document.removeEventListener(
"webkitvisibilitychange",
onVisibilityChange,
false);
main();
}
document.addEventListener(
"webkitvisibilitychange",
onVisibilityChange,
false);
}