Javascript Firefox WebExtensions browser.tabs.query()返回的不可访问数组。有人能解释一下原因吗?
有人能给我解释一下这里发生了什么事吗?我正在玩FirefoxWebExtensionsAPI,我遇到了一些相当奇怪的行为。下面是一些非常简单的代码来说明这个问题 我正在查询所有窗口中的所有固定选项卡,我希望全局数组Javascript Firefox WebExtensions browser.tabs.query()返回的不可访问数组。有人能解释一下原因吗?,javascript,arrays,promise,firefox-addon,firefox-addon-webextensions,Javascript,Arrays,Promise,Firefox Addon,Firefox Addon Webextensions,有人能给我解释一下这里发生了什么事吗?我正在玩FirefoxWebExtensionsAPI,我遇到了一些相当奇怪的行为。下面是一些非常简单的代码来说明这个问题 我正在查询所有窗口中的所有固定选项卡,我希望全局数组var pinted=[]将用选项卡数据/对象填充。然而,至少可以说事情有点反常。数组似乎已填充,但无法使用标准数组表示法pinted[0]返回undefined。我对此感到十分困惑 这是怎么回事?这是关于范围还是权限的问题 现在代码 [manifest.json] { "mani
var pinted=[]代码>将用选项卡数据/对象填充。然而,至少可以说事情有点反常。数组似乎已填充,但无法使用标准数组表示法pinted[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
}
}
[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开发者工具控制台中键入pinted[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
。它返回一个承诺,,但没有立即解决。因此,您暂时不进入然后部分,因此代码执行继续到下一部分
这是console.debug(“所有固定选项卡”,固定)代码>。您正在记录一个数组,因此给console.debug
一个数组引用,这在这里非常重要。此引用不会随时间而更改:当您声明固定的
数组以及脚本结束时,数组引用仍然相同李>
然后转到console.debug(“第一个固定选项卡”,固定[0])代码>。此时,承诺处理程序尚未执行,因此reforepinted
仍然为空,pinted[0]
实际上是未定义的。这就是未定义的被记录的原因
承诺解决了:您通过然后
处理程序,接收标签列表作为参数,并将标签推到您的固定的
数组中
请记住,您的第一个控制台.debug
根据阵列引用记录阵列,该引用不会随时间变化。之后在控制台中查看阵列时,阵列已填充,您在控制台中访问的是处于最终状态的阵列。这就是为什么整个阵列的日志会打印阵列本身
让我们确定一下
…通过一个小测试:在步骤2,我们不记录固定的
数组本身,而是记录当前在固定的
中的所有元素的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
如何处理?
解决方案是在第一个承诺的末尾链接另一个承诺(这是可能的,因为每个处理程序返回一个新的承诺,因此您可以链接它们),如下所示:
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 … }
请注意,不必为数组操作全局变量,您可以使第一个承诺返回一个数组,该数组将作为第二个承诺的参数。这实际上是异步代码和数组引用的问题。
让我们一步一步地试着看看这是怎么回事:
您可以调用browser.tabs.query
。它返回一个承诺,,但没有立即解决。因此,您暂时不进入然后部分,因此代码执行继续到下一部分
这是console.debug(“所有固定选项卡”,固定)代码>。您正在记录一个数组,因此给console.debug
一个数组引用,这在这里非常重要。此引用不会随时间而更改:当您声明固定的
数组以及脚本结束时,数组引用仍然相同李>
然后转到console.debug(“第一个固定选项卡”,固定[0])代码>。此时,承诺处理程序尚未执行,因此reforepinted
仍然为空,pinted[0]
实际上是未定义的。这就是未定义的被记录的原因
承诺解决了:您通过然后
处理程序,接收标签列表作为参数,并将标签推到您的固定的
数组中
请记住,您的第一个控制台.debug
根据阵列引用记录阵列,该引用不会随时间变化。之后在控制台中查看阵列时,阵列已填充,您在控制台中访问的是处于最终状态的阵列。这就是为什么整个阵列的日志会打印阵列本身
让我们确定一下
…通过一个小测试:在步骤2,我们不记录固定的
数组本身,而是记录当前在固定的
中的所有元素的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
如何处理?
解决方案是在第一个承诺的末尾链接另一个承诺(这是可能的,因为每个处理程序返回一个新的承诺,因此您可以链接它们),如下所示:
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 … }
请注意,您可以让第一个承诺返回一个数组,作为第二个承诺的参数,而不是为数组操作全局变量