访问服务工作者通过Chrome Runtime Messaging从内容脚本中保存了索引数据
在Chrome扩展程序中,我的服务工作者使用Chrome Runtime消息传递从我的内容脚本发送的Chrome Runtime Message访问了/从索引DB的数据库中添加,更新和删除数据毫无疑问。我的麻烦是从我的内容脚本中读取完整的表格。在我在Chrome运行时消息传递中将其发送回我的sendResponse之前,我会做一个console.log()丢弃属性,然后我正确地看到了数据,但是内容脚本会收到一个noffined
。我认为这是因为获取数据的异步性质。我尝试了承诺和异步/等待及其组合,但我似乎无法在我的内容脚本中的未定义的
中获得任何东西,从服务工作者回来的消息。我还运行了一个测试阵列,但效果很好 - 但是接收索引的表数据数据在消息传递中不起作用。我还试图json json数据,这也无济于事。什么是捕获?
service-worker.js
importScripts('modules/idb.js');
var SW = {};
SW.onReady = function(){
chrome.runtime.onMessage.addListener(function(o, sender, sendResponse) {
(o.readTable) && sendResponse(SW.readTable(o,sender));
});
};
SW.readTable = function(o,sender){
var sTable = o.table;
new Promise((resolve) => {
IDB.readTable(sTable,function(asEntries){
resolve(asEntries);
});
}).then((asEntries) => {
console.log('SW asEntries',asEntries); // this shows me valid data in tests
var o = {};
// can also change this to fake data with asEntries being a string array and bug goes away in content.js
o.response = asEntries;
return o;
});
};
SW.onReady();
模块/idb.js
var IDB = {};
// Requires storage (or, even better, unlimitedStorage) permission in your manifest.json file.
// Note also that dev console of service worker will not show data -- have to use toolbar button popup panel (if you have one) and
// dev console from there, or code to access it, which sucks.
IDB.connectStore = function(sTable,sReadWriteSetting,fn){
var conn = indexedDB.open('unlimitedStorage', 1);
conn.onupgradeneeded = function(e) {
var db = e.target.result;
db.createObjectStore(sTable);
};
conn.onsuccess = function(e) {
var db = e.target.result;
var tx = db.transaction(sTable,sReadWriteSetting);
var store = tx.objectStore(sTable);
fn(db,tx,store);
};
};
IDB.addToTable = function(sTable,sKey,sVal){
IDB.connectStore(sTable,'readwrite',function(db,tx,store){
if ((sKey === undefined) || (sKey === '') || (sKey === null) || (sKey === false)) { // auto key by increment
var req = store.count();
req.onsuccess = function(e){
sKey = e.target.result + 1;
store.add(sVal,sKey);
tx.complete;
}
} else {
store.add(sVal,sKey);
tx.complete;
}
});
};
IDB.removeFromTable = function(sTable,sKey){
IDB.connectStore(sTable,'readwrite',function(db,tx,store){
store.delete(sKey);
tx.complete;
});
};
IDB.readTableByKey = function(sTable,sKey,fn){
IDB.connectStore(sTable,'readonly',function(db,tx,store){
var req = store.get(sKey);
req.onerror = function(e){
fn(e.target.result);
}
req.onsuccess = function(e){
fn(e.target.result);
}
});
};
IDB.readTable = function(sTable,fn){
IDB.connectStore(sTable,'readonly',function(db,tx,store){
var req = store.getAll();
req.onerror = function(e){
fn(e.target.result);
}
req.onsuccess = function(e){
fn(e.target.result);
}
});
};
content.js
var CONTENT = {};
CONTENT.onReady = function(){
var o = {};
o.readTable = true;
o.table = 'loadTimes';
chrome.runtime.sendMessage(o,function(response){
if (response.response) { // errors here with response property being undefined
console.log('CONTENT RCVD asEntries',response.response);
}
});
};
CONTENT.onReady();
In a Chrome Extension, I have no problem adding, updating, and removing data to/from an IndexedDB database accessed by my service worker with Chrome Runtime Messaging sent from my content script. My trouble is doing a full table read from my content script. I do a console.log() to dump out the property before I send it back in my sendResponse in the Chrome Runtime Messaging, and I see the data there properly, but the content script receives an undefined
. I assume this is because of the asynchronous nature of getting the data. I tried promises and async/await and the combination thereof and I just can't seem to get anything except an undefined
in my content script on the message back from the service worker. I also ran sending a test array back and that worked just fine -- but receiving the IndexedDB table data does not work in the message passing. I also tried to JSONify the data and that didn't help either. What's the catch?
service-worker.js
importScripts('modules/idb.js');
var SW = {};
SW.onReady = function(){
chrome.runtime.onMessage.addListener(function(o, sender, sendResponse) {
(o.readTable) && sendResponse(SW.readTable(o,sender));
});
};
SW.readTable = function(o,sender){
var sTable = o.table;
new Promise((resolve) => {
IDB.readTable(sTable,function(asEntries){
resolve(asEntries);
});
}).then((asEntries) => {
console.log('SW asEntries',asEntries); // this shows me valid data in tests
var o = {};
// can also change this to fake data with asEntries being a string array and bug goes away in content.js
o.response = asEntries;
return o;
});
};
SW.onReady();
modules/idb.js
var IDB = {};
// Requires storage (or, even better, unlimitedStorage) permission in your manifest.json file.
// Note also that dev console of service worker will not show data -- have to use toolbar button popup panel (if you have one) and
// dev console from there, or code to access it, which sucks.
IDB.connectStore = function(sTable,sReadWriteSetting,fn){
var conn = indexedDB.open('unlimitedStorage', 1);
conn.onupgradeneeded = function(e) {
var db = e.target.result;
db.createObjectStore(sTable);
};
conn.onsuccess = function(e) {
var db = e.target.result;
var tx = db.transaction(sTable,sReadWriteSetting);
var store = tx.objectStore(sTable);
fn(db,tx,store);
};
};
IDB.addToTable = function(sTable,sKey,sVal){
IDB.connectStore(sTable,'readwrite',function(db,tx,store){
if ((sKey === undefined) || (sKey === '') || (sKey === null) || (sKey === false)) { // auto key by increment
var req = store.count();
req.onsuccess = function(e){
sKey = e.target.result + 1;
store.add(sVal,sKey);
tx.complete;
}
} else {
store.add(sVal,sKey);
tx.complete;
}
});
};
IDB.removeFromTable = function(sTable,sKey){
IDB.connectStore(sTable,'readwrite',function(db,tx,store){
store.delete(sKey);
tx.complete;
});
};
IDB.readTableByKey = function(sTable,sKey,fn){
IDB.connectStore(sTable,'readonly',function(db,tx,store){
var req = store.get(sKey);
req.onerror = function(e){
fn(e.target.result);
}
req.onsuccess = function(e){
fn(e.target.result);
}
});
};
IDB.readTable = function(sTable,fn){
IDB.connectStore(sTable,'readonly',function(db,tx,store){
var req = store.getAll();
req.onerror = function(e){
fn(e.target.result);
}
req.onsuccess = function(e){
fn(e.target.result);
}
});
};
content.js
var CONTENT = {};
CONTENT.onReady = function(){
var o = {};
o.readTable = true;
o.table = 'loadTimes';
chrome.runtime.sendMessage(o,function(response){
if (response.response) { // errors here with response property being undefined
console.log('CONTENT RCVD asEntries',response.response);
}
});
};
CONTENT.onReady();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
与Firefox Webexensions不同,Chrome Extensions API无法处理从回调中返回的承诺或在SendResponse中提供的承诺, htttps:httpps:// crbug。 com/1185241 。
您的可读取中还有一个错误:您需要在
new Promise(((lasesolve)
)之前添加return
该解决方案是双重的:
返回true true
从回调中允许异步sendResponsesendreponse
。
Chrome extensions API, unlike Firefox WebExtensions, can't handle Promise returned from a callback or provided in sendResponse, https://crbug.com/1185241.
There's also a bug in your readTable: you need to add
return
beforenew Promise((resolve)
The solution is two-fold:
return true
from the callback to allow asynchronous sendResponsesendReponse
inside.then
of a Promise chain.不要使用此答案。它是出于后代原因而在这里,只是一个解决方法。所选解决方案的作品。
修复程序是在其他消息线程中返回数据:
在
sw.readtable()
中的服务工作者中,只需返回变量o
o < /code>带有
o.Response = true
,然后忽略内容脚本中的响应。从
sw.readtable()
返回变量之前函数(响应){/ *忽略响应 */});在内容脚本中,请忽略从
读取
消息中回来的任何响应。因此,if(response.response){...}
可以消除条件。在内容脚本中,添加一个消息侦听器,
chrome.runtime.onmessage.Addlistener(O,Sender,SendResponse)
并查找条件(o.ReadTableReSult)
。收到后,o.data
现在将包含asentries
data。Do not use this answer. It is here for posterity reasons and is just a workaround. The chosen solution works.
The fix is to return data in a different message thread:
In the service worker in
SW.readTable()
, just return variableo
witho.response = true
and then ignore the response in the content script.Before returning the variable
o
fromSW.readTable()
, do achrome.runtime.sendMessage({readTableResult = true, data: asEntries},function(response){ /* ignore response */});
In the content script, ignore any response back from the
readTable
message. So, theif (response.response) {...}
condition can be eliminated.In the content script, add a message listener with
chrome.runtime.onMessage.addListener(o, sender, sendResponse)
and look for the condition(o.readTableResult)
. Once received, theo.data
will now contain theasEntries
data.