I am trying to write a Foxfire web extension. I want a function that returns the URL of a tab.
Firefox tabs browser.tabs.get(id)
returns a promise that resolves to a tab object that has a member with the URL. browser.tabs.query
returns a promise that resolves to a tabs array which contains the id of the tabs.
Plan wrap the two calls above in a promise that resolves to the tab.url Use async/await to wait for it to resolve and return the result.
According to the MDN documentation:
"The await expression causes async function execution to pause until a Promise is fulfilled, that is resolved or rejected, and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise."
The manifest file has the tabs permission.
So my code is below:
browser.browserAction.onClicked.addListener(test);
async function test(){
let res = await GetActiveTabURL();
//console.log(`test ${res}`);
return res;
}
async function test2(TabID){
let res = await GetTabURL(TabID);
//console.log(`test2 ${res}`);
return res;
}
function GetActiveTabURL() {
return new Promise((resolve, reject) => {
browser.tabs.query({currentWindow: true, active: true})
.then((tabs) => {
browser.tabs.get(tabs.pop().id)
.then((tab) => {
//console.dir(tab);
resolve(tab.url)
})
})
})
}
function GetTabURL(TabID) {
return new Promise((resolve, reject) => {
browser.tabs.get(TabID)
.then((tab) => {
//console.dir(tab);
resolve(tab.url)
})
})
}
As shown the console.dir and console.log statements are mented out. I debug the code and use the mand line to execute the test functions. I (and I am apparently wrong) think the await in the test functions should wait until the promise resolves and then let me return the values.
Ok if I unment the console.log and console.dir statements, running the test from the mand line gives the expected (url)result. In the console I see the results of the log/dir statements and, when run from the mand line the final result is the URL of the tab (you can get the tab.id from the console.dir for test2).
If I ment out the console.dir statements I get a line in the log that says, "Promise { : "pending" }" followed immediately by the desired result (the url) on a new line.
if I then ment out the console.log statements as well, I ONLY get the "Promise { : "pending" }" line. I NEVER get the desired URL.
the manifest file follows if anyone wants to try this:
{
"manifest_version": 2,
"name": "TestGetURL",
"description": "Functions returning the url",
"version": "1.0",
"icons": {
"48": "icons/link-48.png"
},
"permissions": [
"tabs",
"contextMenus",
"nativeMessaging",
"<all_urls>",
"webRequest",
"downloads",
"clipboardWrite",
"webNavigation",
"notifications",
"storage",
"cookies",
"alarms"
],
"background": {
"scripts": ["background-script.js"]
},
"browser_action": {
"browser_style":false,
"default_icon": {
"16": "icons/page-16.png",
"32": "icons/page-32.png"
}
},
"default_locale": "en"
}
I am trying to write a Foxfire web extension. I want a function that returns the URL of a tab.
Firefox tabs browser.tabs.get(id)
returns a promise that resolves to a tab object that has a member with the URL. browser.tabs.query
returns a promise that resolves to a tabs array which contains the id of the tabs.
Plan wrap the two calls above in a promise that resolves to the tab.url Use async/await to wait for it to resolve and return the result.
According to the MDN documentation:
"The await expression causes async function execution to pause until a Promise is fulfilled, that is resolved or rejected, and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise."
The manifest file has the tabs permission.
So my code is below:
browser.browserAction.onClicked.addListener(test);
async function test(){
let res = await GetActiveTabURL();
//console.log(`test ${res}`);
return res;
}
async function test2(TabID){
let res = await GetTabURL(TabID);
//console.log(`test2 ${res}`);
return res;
}
function GetActiveTabURL() {
return new Promise((resolve, reject) => {
browser.tabs.query({currentWindow: true, active: true})
.then((tabs) => {
browser.tabs.get(tabs.pop().id)
.then((tab) => {
//console.dir(tab);
resolve(tab.url)
})
})
})
}
function GetTabURL(TabID) {
return new Promise((resolve, reject) => {
browser.tabs.get(TabID)
.then((tab) => {
//console.dir(tab);
resolve(tab.url)
})
})
}
As shown the console.dir and console.log statements are mented out. I debug the code and use the mand line to execute the test functions. I (and I am apparently wrong) think the await in the test functions should wait until the promise resolves and then let me return the values.
Ok if I unment the console.log and console.dir statements, running the test from the mand line gives the expected (url)result. In the console I see the results of the log/dir statements and, when run from the mand line the final result is the URL of the tab (you can get the tab.id from the console.dir for test2).
If I ment out the console.dir statements I get a line in the log that says, "Promise { : "pending" }" followed immediately by the desired result (the url) on a new line.
if I then ment out the console.log statements as well, I ONLY get the "Promise { : "pending" }" line. I NEVER get the desired URL.
the manifest file follows if anyone wants to try this:
{
"manifest_version": 2,
"name": "TestGetURL",
"description": "Functions returning the url",
"version": "1.0",
"icons": {
"48": "icons/link-48.png"
},
"permissions": [
"tabs",
"contextMenus",
"nativeMessaging",
"<all_urls>",
"webRequest",
"downloads",
"clipboardWrite",
"webNavigation",
"notifications",
"storage",
"cookies",
"alarms"
],
"background": {
"scripts": ["background-script.js"]
},
"browser_action": {
"browser_style":false,
"default_icon": {
"16": "icons/page-16.png",
"32": "icons/page-32.png"
}
},
"default_locale": "en"
}
Share
Improve this question
edited Feb 19, 2018 at 11:22
WebDevBooster
15k9 gold badges68 silver badges70 bronze badges
asked Feb 19, 2018 at 8:57
Charles BisbeeCharles Bisbee
4011 gold badge5 silver badges10 bronze badges
5
-
2
Avoid the
Promise
constructor antipattern! – Bergi Commented Feb 19, 2018 at 8:58 - "If I unment the console.log and console.dir statments, running the test from the mand line gives the expected (url)result." - so then just do that? – Bergi Commented Feb 19, 2018 at 9:00
-
2
An
await
does not make the code synchronous, it is still anasync function
that will return a promise. – Bergi Commented Feb 19, 2018 at 9:01 -
first thing I spotted ... you'll want to return
browser.tabs.get
– Jaromanda X Commented Feb 19, 2018 at 9:27 - Bergi, why make ments such as "so then just do it". They are of no help. Even if it works something is wrong and it is likely not to work in some other context. Explaining what is wrong would be helpful. Your second one actually contains the germ of the answer but, as I said, i am new so it's not enough. – Charles Bisbee Commented Feb 20, 2018 at 9:37
2 Answers
Reset to default 2Found in documentation that async function MUST return a promise. Any return statement. The value of a return statement that does not contain a promise is ignored as shown above. Apparently the last promise in the function is returned.
So, as far as I can see, you cannot write a function that waits for a promise returns the value from that promise.
the value from let xx = await promise, xx is available in the same function after the await statement and can be used there. So rather than calling a function to asynchronously return a value, you must make the calling function async and use a series of awaits as necessary to get to the value you want, then use it within the function.
Try this, remember if you have the environment to use async/await then favor that overusing .then().
browser.browserAction.onClicked.addListener(test);
async function test() {
let res = await GetActiveTabURL();
return res;
}
async function test2(TabID) {
let res = await GetTabURL(TabID);
return res;
}
async function GetActiveTabURL() {
const tabs = await browser.tabs.query({
currentWindow: true,
active: true
});
const tab = browser.tabs.get(tabs.pop().id);
return tab.url;
}
async function GetTabURL() {
const tab = await browser.tabs.get(TabID);
return tab.url;
}