[英]Inaccessible array returned by Firefox WebExtensions browser.tabs.query(). Can someone explain why?
有人可以告诉我这是怎么回事吗? 我正在使用Firefox WebExtensions API,并且遇到了一些非常奇怪的行为。 这是一些非常简单的代码来说明问题。
我正在查询所有窗口中的所有固定选项卡,并且期望全局数组var pinned = [];
将使用标签数据/对象填充。 但是,至少可以说这有点棘手。 该数组似乎已填充,但使用标准数组符号pinned[0]
不能访问undefined
无法访问各个元素。 我对此感到非常困惑。
那么这是怎么回事? 这是有关范围或权限的问题吗?
现在的代码...
[manifest.json]
{
"manifest_version": 2,
"name": "test",
"version": "1.0",
"description": "test",
"icons": {
"48": "icons/page-48_white.png"
},
"permissions": [
"tabs",
"<all_urls>"
],
"background": {
"scripts": ["background.js"]
},
"devtools_page": "test.html",
"browser_action": {
"default_icon": { "48": "icons/page-48_white.png"},
"default_title": "Test",
"browser_style": true
}
}
[background.js]
function createExtPage(){
browser.tabs.create({ "url": "test.html" });
}
browser.browserAction.onClicked.addListener(createExtPage);
[test.js]
var pinned = [];
browser.tabs.query({pinned: true})
.then(tabs => {
for (let [key, value] of tabs.entries() ) {
console.log("Object " + key, value);
pinned.push(value);
}
});
console.debug("All Pinned Tabs", pinned);
console.debug("First Pinned Tab", pinned[0]);
现在来看一下Firefox开发者工具控制台的输出。
All Pinned Tabs
[]
0: {…}
active: false
audible: false
discarded: false
favIconUrl: "http://www.crunchyroll.com/favicon.ico?v=1"
height: 800
hidden: false
highlighted: false
id: 149
incognito: false
index: 0
isArticle: false
isInReaderMode: false
lastAccessed: 1522229700160
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "Crunchyroll - Watch Naruto Shippuden, Bleach, Anime Videos and Episodes Free Online"
url: "http://www.crunchyroll.com/"
width: 1440
windowId: 3
__proto__: Object { … }
1: {…}
active: false
audible: false
discarded: false
favIconUrl: "https://www.pandora.com/favicon.ico"
height: 800
hidden: false
highlighted: false
id: 145
incognito: false
index: 0
isArticle: false
isInReaderMode: false
lastAccessed: 1522447564848
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "All Along The Watchtower Radio - Now Playing on Pandora"
url: "https://www.pandora.com/station/play/3395036678172411653"
width: 1440
windowId: 67
__proto__: Object { … }
2: {…}
active: false
audible: false
discarded: false
height: 800
hidden: false
highlighted: false
id: 171
incognito: false
index: 1
isArticle: false
isInReaderMode: false
lastAccessed: 1522398347238
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "Debugging with Firefox Developer Tools"
url: "about:debugging"
width: 1440
windowId: 67
__proto__: Object { … }
length: 3
__proto__: Array []
First Pinned Tab undefined
Object 0
{…}
active: false
audible: false
discarded: false
favIconUrl: "http://www.crunchyroll.com/favicon.ico?v=1"
height: 800
hidden: false
highlighted: false
id: 149
incognito: false
index: 0
isArticle: false
isInReaderMode: false
lastAccessed: 1522229700160
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "Crunchyroll - Watch Naruto Shippuden, Bleach, Anime Videos and Episodes Free Online"
url: "http://www.crunchyroll.com/"
width: 1440
windowId: 3
__proto__: Object { … }
Object 1
{…}
active: false
audible: false
discarded: false
favIconUrl: "https://www.pandora.com/favicon.ico"
height: 800
hidden: false
highlighted: false
id: 145
incognito: false
index: 0
isArticle: false
isInReaderMode: false
lastAccessed: 1522447564848
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "All Along The Watchtower Radio - Now Playing on Pandora"
url: "https://www.pandora.com/station/play/3395036678172411653"
width: 1440
windowId: 67
__proto__: Object { … }
Object 2
{…}
active: false
audible: false
discarded: false
height: 800
hidden: false
highlighted: false
id: 171
incognito: false
index: 1
isArticle: false
isInReaderMode: false
lastAccessed: 1522398347238
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "Debugging with Firefox Developer Tools"
url: "about:debugging"
width: 1440
windowId: 67
__proto__: Object { … }
这是真正棘手的事情。 如果我在firefox开发人员工具控制台中键入pinned[0]
,我将得到此结果
pinned[0]
{…}
active: false
audible: false
discarded: false
favIconUrl: "http://www.crunchyroll.com/favicon.ico?v=1"
height: 800
hidden: false
highlighted: false
id: 149
incognito: false
index: 0
isArticle: false
isInReaderMode: false
lastAccessed: 1522229700160
mutedInfo: Object { muted: false }
pinned: true
sharingState: Object { camera: false, microphone: false }
status: "complete"
title: "Crunchyroll - Watch Naruto Shippuden, Bleach, Anime Videos and Episodes Free Online"
url: "http://www.crunchyroll.com/"
width: 1440
windowId: 3
__proto__: Object { … }
是什么赋予了? 为什么我可以从控制台访问数组的元素,但不能从代码访问?
如您所见,固定的数组已填充,但我无法使用该数组访问其中的各个元素。 有人知道为什么会这样吗?
这实际上是异步代码和数组引用的问题。 让我们尝试一步一步来看看如何进行:
browser.tabs.query
。 它返回一个承诺, 但不能立即解决 。 因此,你不进入then
一部分暂时的,所以执行代码继续到下一部分... console.debug("All Pinned Tabs", pinned);
。 您正在记录一个数组,因此您要为console.debug
提供对该数组的引用 ,这在这里确实很重要。 该引用不会随时间变化:当您声明pinned
数组并且脚本结束时,该数组引用仍将相同。 console.debug("First Pinned Tab", pinned[0]);
。 此时,尚未执行Promise处理程序,因此pinned
仍然为空,而pinned[0]
实际上是undefined
。 这就是undefined
被记录的原因。 then
处理程序,将tabs列表作为参数接收, then
将tabs推入pinned
数组。 记住,您的第一个console.debug
基于数组引用记录了该数组,该记录没有随着时间的推移而改变 。 之后,当您在控制台中查看阵列时,此阵列已被填充,您在控制台中访问的是处于最终状态的阵列。 这就是为什么整个数组的日志确实会打印数组本身的原因。
...进行一些测试:在第2步,而不是记录pinned
数组本身,让我们记录当前在pinned
的所有元素的id
。
var pinned = [];
browser.tabs.query({pinned: true})
.then(tabs => {
for (let [key, value] of tabs.entries() ) {
console.log("Object " + key, value);
pinned.push(value);
}
});
// will log an empty array since pinned tab is still empty,
// therefore, mapping tab ids will return an empty array
console.warn("All Pinned Tabs", pinned.map((t) => t.id));
// still undefined, nothing changed here
console.warn("First Pinned Tab", pinned[0]);
这是您应该得到的:
All Pinned Tabs : Array []
First Pinned Tab undefined
一种解决方案是在第一个promise的末尾链接另一个promise (之所以成为可能,因为每个then
处理程序都返回一个新的promise,因此您可以链接它们) ,如下所示:
var pinned = [];
browser.tabs.query({pinned: true})
.then(tabs => {
for (let [key, value] of tabs.entries() ) {
console.log("Object " + key, value);
pinned.push(value);
}
}).then( () => {
// ✓ [1,4,3,2] or anything matching your tabs ids
console.debug("All Pinned Tabs", pinned.map((t) => t.id));
// ✓ First tab object: { ... }
console.debug("First Pinned Tab", pinned[0]);
});
现在您确实获得了预期的结果:
All Pinned Tabs Array(4) [ 1, 4, 3, 2 ]
First Pinned Tab Object { id: 1, index: 0, windowId: 3, highlighted: false … }
请注意,您可以使第一个Promise返回一个数组,该数组将作为第二个Promise的参数,而不是为数组操作全局变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.