在Chrome扩展中,我可以通过内容脚本发送的Chrome Runtime Messaging向/从服务人员访问的IndexedDB数据库中添加、更新和删除数据。我的问题是从内容脚本读取完整的表。我创建了console.log()在Chrome Runtime Messaging的sendResponse中发送回属性之前转储该属性,我可以在那里正确地看到数据,但是内容脚本收到了一个undefined
。我认为这是因为获取数据的异步特性。我尝试了promises和async/await以及它们的组合,但是除了在内容脚本中从服务工作者返回的消息中得到一个undefined
之外,我似乎什么也得不到。我还运行了发回一个测试数组的过程,结果很好--但是接收IndexedDB表数据在消息传递中不起作用。我还尝试对数据进行JSON化,结果也没有帮助。问题是什么?
服务工作者.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);
}
});
};
内容.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();
2条答案
按热度按时间ou6hu8tu1#
与Firefox WebExtensions不同,Chrome扩展API无法处理回调返回的或sendResponse中提供的Promise,https://crbug.com/1185241。
readTable中也有一个错误:您需要在
new Promise((resolve)
之前添加return
解决方案有两个方面:
1.使用回调中的
return true
以允许异步sendResponse1.在Promise链的
.then
内调用sendReponse
。mmvthczy2#
请勿使用此答案。此处提供此答案是为了方便后人使用,只是一种变通方法。所选的解决方案有效。
修复方法是在不同的消息线程中返回数据:
1.在
SW.readTable()
中的service worker中,只需返回变量o
和o.response = true
,然后忽略内容脚本中的响应。1.在从
SW.readTable()
返回变量o
之前,执行chrome.runtime.sendMessage({readTableResult = true, data: asEntries},function(response){ /* ignore response */});
1.在内容脚本中,忽略从
readTable
消息返回的任何响应。因此,可以消除if (response.response) {...}
条件。1.在内容脚本中,添加一个包含
chrome.runtime.onMessage.addListener(o, sender, sendResponse)
的消息监听程序,并查找条件(o.readTableResult)
。一旦接收到o.data
,o.data
现在将包含asEntries
数据。