I just can't get my head around this stuff :(
compatibleApps: async () => {
common.header('Install Compatible Apps')
const compatibleApps = JSON.parse(fs.readFileSync('./data/compatibleApps.json', 'utf8'));
const value = await inquirer.compatibleApps();
for (let element of value.removeAppsList) {
for (let element2 of compatibleApps) {
if (element === element2.name) {
await files.downloadFile(element2)
}
}
}
await adb.installApk()
},
await adb.installApk() is being executed before the all calls of await files.downloadFile(element2 ) have been completed..
Below is the contents of downloadFile, I guess I need to wrap it in a promise?
downloadFile: async (element) => {
option = {
dir: './data/apps',
onDone: (info)=>{
console.log('Latest ' + element.name + ' Downloaded')
},
onError: (err) => {
console.log('error', err);
},
onProgress: (curr, total) => {
},
}
var dd = await dl(element.url, option);
}
Keep in mind that await only does anything useful if you are awaiting a promise that is linked to your actual asynchronous operation. "Linked" in that sentence means that the promise resolves when the asynchronous operation is done or rejected if it has an error.
If the function you are awaiting either returns nothing or returns just a plain value, yet contains asynchronous operations, then the await doesn't actually await anything. It calls the function, initiates those asynchronous operations, the function returns a non-promise value or returns an already resolved promise, the await doesn't have a anything to wait for and just continues executing more lines of code without the expected pause for the asynchronous operations to complete.
So, in your code, the only way that:
await adb.installApk()
executes before any of the calls to:
await files.downloadFile(element2)
is if files.downloadFile() does not actually return a promise that is linked to the asynchronous operations it contains or perhaps if you never execute files.downloadFile(element2) because of the conditionals.
For more specific help, show us the code for files.downloadFile() and confirm that you are getting through your conditionals and executing it at least once.
Related
I have the following JS code
async function readAtlasAll() {
return await MongoClient.connect(url, async function(err, db) {
var dbo = db.db("Users");
c = dbo.collection("List");
r = await c.find({}).toArray();
console.log(r);
return r;
});
}
console.log(readAtlasAll());
I'm not sure why, but printing the result of readAtlasAll() comes before printing the variable r inside the function, even though I'm awaiting the result of r beforehand. The terminal prints Promise { <pending> } first and afterwards prints the contents of r.
I'm relatively new to JavaScript, so I would really appreciate the help. Thanks!
You cannot use both await and a plain callback on MongoDB API calls as the await won't do anything useful. Use one or the other, not both. This is because the MongoDB asynchronous APIs will return a promise if you do NOT pass a callback to them and you can then await that promise, but if you pass a callback, they do not return a promise, therefore the await does nothing useful at all. Here's how you would implement it by leaving out the callback and using await:
async function readAtlasAll() {
const db = await MongoClient.connect(url);
const dbo = db.db("Users");
const c = dbo.collection("List");
const r = await c.find({}).toArray();
return r; // this will be the resolved value of the returned promise
}
readAtlasAll().then(r => {
console.log(r);
}).catch(err => {
console.log(err);
});
Keep in mind that await has no magic powers at all. ALL it does is suspend execution of the function until a promise resolves/rejects. So, it only does anything useful when you await a promise.
And, further, ALL async functions return a promise so there is NO way to return an asynchronously-retrieved value directly from your function. You have to use an asynchronous mechanism for communicating back an asynchronously retrieved value such as a promise, a callback or an event. So readAtlasAll() can never return your value directly.
See How to return the response from an asynchronous call for more info on that.
Given the code samples below, is there any difference in behavior, and, if so, what are those differences?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
As I understand it, the first would have error-handling within the async function, and errors would bubble out of the async function's Promise. However, the second would require one less tick. Is this correct?
This snippet is just a common function to return a Promise for reference.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
Most of the time, there is no observable difference between return and return await. Both versions of delay1Second have the exact same observable behavior (but depending on the implementation, the return await version might use slightly more memory because an intermediate Promise object might be created).
However, as #PitaJ pointed out, there is one case where there is a difference: if the return or return await is nested in a try-catch block. Consider this example
async function rejectionWithReturnAwait () {
try {
return await Promise.reject(new Error())
} catch (e) {
return 'Saved!'
}
}
async function rejectionWithReturn () {
try {
return Promise.reject(new Error())
} catch (e) {
return 'Saved!'
}
}
In the first version, the async function awaits the rejected promise before returning its result, which causes the rejection to be turned into an exception and the catch clause to be reached; the function will thus return a promise resolving to the string "Saved!".
The second version of the function, however, does return the rejected promise directly without awaiting it within the async function, which means that the catch case is not called and the caller gets the rejection instead.
As other answers mentioned, there is likely a slight performance benefit when letting the promise bubble up by returning it directly — simply because you don’t have to await the result first and then wrap it with another promise again. However, no one has talked about tail call optimization yet.
Tail call optimization, or “proper tail calls”, is a technique that the interpreter uses to optimize the call stack. Currently, not many runtimes support it yet — even though it’s technically part of the ES6 Standard — but it’s possible support might be added in the future, so you can prepare for that by writing good code in the present.
In a nutshell, TCO (or PTC) optimizes the call stack by not opening a new frame for a function that is directly returned by another function. Instead, it reuses the same frame.
async function delay1Second() {
return delay(1000);
}
Since delay() is directly returned by delay1Second(), runtimes supporting PTC will first open a frame for delay1Second() (the outer function), but then instead of opening another frame for delay() (the inner function), it will just reuse the same frame that was opened for the outer function. This optimizes the stack because it can prevent a stack overflow (hehe) with very large recursive functions, e.g., fibonacci(5e+25). Essentially it becomes a loop, which is much faster.
PTC is only enabled when the inner function is directly returned. It’s not used when the result of the function is altered before it is returned, for example, if you had return (delay(1000) || null), or return await delay(1000).
But like I said, most runtimes and browsers don’t support PTC yet, so it probably doesn’t make a huge difference now, but it couldn’t hurt to future-proof your code.
Read more in this question: Node.js: Are there optimizations for tail calls in async functions?
Noticeable difference: Promise rejection gets handled at different places
return somePromise will pass somePromise to the call site, and await somePromise to settle at call site (if there is any). Therefore, if somePromise is rejected, it will not be handled by the local catch block, but the call site's catch block.
async function foo () {
try {
return Promise.reject();
} catch (e) {
console.log('IN');
}
}
(async function main () {
try {
let a = await foo();
} catch (e) {
console.log('OUT');
}
})();
// 'OUT'
return await somePromise will first await somePromise to settle locally. Therefore, the value or Exception will first be handled locally. => Local catch block will be executed if somePromise is rejected.
async function foo () {
try {
return await Promise.reject();
} catch (e) {
console.log('IN');
}
}
(async function main () {
try {
let a = await foo();
} catch (e) {
console.log('OUT');
}
})();
// 'IN'
Reason: return await Promise awaits both locally and outside, return Promise awaits only outside
Detailed Steps:
return Promise
async function delay1Second() {
return delay(1000);
}
call delay1Second();
const result = await delay1Second();
Inside delay1Second(), function delay(1000) returns a promise immediately with [[PromiseStatus]]: 'pending. Let's call it delayPromise.
async function delay1Second() {
return delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
Async functions will wrap their return value inside Promise.resolve()(Source). Because delay1Second is an async function, we have:
const result = await Promise.resolve(delayPromise);
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
Promise.resolve(delayPromise) returns delayPromise without doing anything because the input is already a promise (see MDN Promise.resolve):
const result = await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
await waits until the delayPromise is settled.
IF delayPromise is fulfilled with PromiseValue=1:
const result = 1;
ELSE is delayPromise is rejected:
// jump to catch block if there is any
return await Promise
async function delay1Second() {
return await delay(1000);
}
call delay1Second();
const result = await delay1Second();
Inside delay1Second(), function delay(1000) returns a promise immediately with [[PromiseStatus]]: 'pending. Let's call it delayPromise.
async function delay1Second() {
return await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
Local await will wait until delayPromise gets settled.
Case 1: delayPromise is fulfilled with PromiseValue=1:
async function delay1Second() {
return 1;
}
const result = await Promise.resolve(1); // let's call it "newPromise"
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: 1
const result = 1;
Case 2: delayPromise is rejected:
// jump to catch block inside `delay1Second` if there is any
// let's say a value -1 is returned in the end
const result = await Promise.resolve(-1); // call it newPromise
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: -1
const result = -1;
Glossary:
Settle: Promise.[[PromiseStatus]] changes from pending to resolved or rejected
This is a hard question to answer, because it depends in practice on how your transpiler (probably babel) actually renders async/await. The things that are clear regardless:
Both implementations should behave the same, though the first implementation may have one less Promise in the chain.
Especially if you drop the unnecessary await, the second version would not require any extra code from the transpiler, while the first one does.
So from a code performance and debugging perspective, the second version is preferable, though only very slightly so, while the first version has a slight legibility benefit, in that it clearly indicates that it returns a promise.
In our project, we decided to always use 'return await'.
The argument is that "the risk of forgetting to add the 'await' when later on a try-catch block is put around the return expression justifies having the redundant 'await' now."
Here is a typescript example that you can run and convince yourself that you need that "return await"
async function test() {
try {
return await throwErr(); // this is correct
// return throwErr(); // this will prevent inner catch to ever to be reached
}
catch (err) {
console.log("inner catch is reached")
return
}
}
const throwErr = async () => {
throw("Fake error")
}
void test().then(() => {
console.log("done")
}).catch(e => {
console.log("outer catch is reached")
});
here i leave some code practical for you can undertand it the diferrence
let x = async function () {
return new Promise((res, rej) => {
setTimeout(async function () {
console.log("finished 1");
return await new Promise((resolve, reject) => { // delete the return and you will see the difference
setTimeout(function () {
resolve("woo2");
console.log("finished 2");
}, 5000);
});
res("woo1");
}, 3000);
});
};
(async function () {
var counter = 0;
const a = setInterval(function () { // counter for every second, this is just to see the precision and understand the code
if (counter == 7) {
clearInterval(a);
}
console.log(counter);
counter = counter + 1;
}, 1000);
console.time("time1");
console.log("hello i starting first of all");
await x();
console.log("more code...");
console.timeEnd("time1");
})();
the function "x" just is a function async than it have other fucn
if will delete the return it print "more code..."
the variable x is just an asynchronous function that in turn has another asynchronous function, in the main of the code we invoke a wait to call the function of the variable x, when it completes it follows the sequence of the code, that would be normal for "async / await ", but inside the x function there is another asynchronous function, and this returns a promise or returns a" promise "it will stay inside the x function, forgetting the main code, that is, it will not print the" console.log ("more code .. "), on the other hand if we put" await "it will wait for every function that completes and finally follows the normal sequence of the main code.
below the "console.log (" finished 1 "delete the" return ", you will see the behavior.
I'm new to promises, so apologize for the newbie question. Inside my function, I have the following lines (middle of the function):
...
const retPromise = await buildImgs(file, imgArray);
retPromise.then(async function () {
console.log("completed build imgs");
...
My assumption was that the "then" from the promise would not execute until the await was completed. but alas, it is acting like sync code, and the retPromise evaluating the "then" before the buildImgs is completed (as measured by my console.log flows). The result is an undefined retPromise.
please help...what am I missing in the concept?
OK: after feedback, let me explaing further my question:
I am trying to understand this async/sync flow and control concept:
const retVal = somefunc();
console.log(retVal);
const retVal = await somefunc();
console.log(retVal);
in the first case, if I understand sync / async code correctly, then I should have a possibility that retVal is undefined when the console.log finds it...
in the second case, I thought it would stop flow until that point that somefunc() completes, then the flow would continue. However my reading seems to indicate it will still try to run the console.log message as a parallel thread. So this leads me to believe I would need to put the console.log inside of the .then after somefunc. Which leads me to promises. So I made a promise return, which I see happening.
However, the .then, as in my original post code, seems to post the console message "completed build imgs", before code inside my buildImgs completes (measured by time I know the function to take, and also console messages inside the buildImgs to help me with sequencing)
so it seems to me I am still missing a fundamental on how to block flow for async code. :(
When you use await construction the script waits until the promise resolves and return to your retPromise value from this promise.
So in this case better to choose one. Remove await and keep then, or keep await and use retPromise value.
Assuming that buildImgs is actually returning a promise (example)
const buildImgs = (file, imgArray) => {
return new Promise((resolve, reject) => {
try {
// ...
resolve()
} catch (err) {
reject(err)
}
})
}
When you call await on a promise its already waiting for the promise to complete, if you remove the await on the call then you can use .then
there are two ways to write promise handlers, the older way looks like this
buildImgs(file, imgArray)
.then(() => {
console.log('im done')
})
.catch(err => {
console.error(err)
})
and the newer syntax
// you must declare "async" in order to use "await"
const asyncFunction = async () => {
try {
await buildImgs(file, imgArray)
console.log('im done')
} catch(err) {
console.error(err)
}
}
asyncFunction()
if you need the return value from the promise, then you would assign it to a variable
const ineedResponse = await buildImgs(file, imgArray)
console.log(ineedResponse)
// or
buildImgs(file, imgArray)
.then(ineedResponse => {
console.log(ineedResponse)
})
.catch(err => {
console.error(err)
})
In my react app, I am making an axios call within a for each loop however, the program doesn't wait for the response of the GET request but rather it executes the next part of the program. When it eventually resolves the promise it is too late. How do I pause the execution of the program until axios has returned from its request.
In a nutshell I need axios to return the result and then continue to run the rest of the program in a synchronous manner.
I have tried using the async/await options however, it doesn't seem to do the trick. I need Axios to run synchronously.
pids.forEach((i1) => loadedContent.forEach((i2, idx) => {
if (i1 === i2.available_versions.version[0].pid || i1 ===
i2.versionPid) {
axios.get(`https://programmes.api.hebel.com/dougi/api/versions?
anshur${i1}`).then((response) => {
xml2js.parseString(response.data, function(err, result) {
loadedContent[idx].nCrid =
result.gui.results[0].vastilp[0].roundup[0].identifier[0]._
alert(loadedContent[idx].nCrid)
//Need it to go into here, however it is bypassing this and
continuing
//on to line 111
});
}).catch(e => {
console.log('error', e);
});
}
}))
I expect axios to run synchronously, or at the very least wait until the promise has been resolved before continuing on.
Doing an asynchronous call would effectively 'pause' the execution until the value is available. With the way your program is currently written with .then(), why don't you try it with fetch?
You can use bluebirds Promise.map method to execute your async code synchronously. Foreach is synchronized function so it's ok that's next loop is starting before first one is ended. Also you can use async await to exec it in a correct order. That's how i will make it with async await and Promise.map:
await Promise.map(pids, async i1 => {
await Promise.map(loadedContent, async (i2, idx) => {
if (i1 === i2.available_versions.version[0].pid || i1 ===
i2.versionPid) {
const response = await axios.get(`https://programmes.api.hebel.com/dougi/api/versions?
anshur${i1}`);
xml2js.parseString(response.data, function (err, result) {
loadedContent[idx].nCrid =
result.gui.results[0].vastilp[0].roundup[0].identifier[0]._
alert(loadedContent[idx].nCrid)
});
});
});
Just going through this tutorial, and it baffles me to understand why await only works in async function.
From the tutorial:
As said, await only works inside async function.
From my understanding, async wraps the function return object into a Promise, so the caller can use .then()
async function f() {
return 1;
}
f().then(alert); // 1
And await just waits for the promise to settle within the async function.
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait till the promise resolves (*)
alert(result); // "done!"
}
f();
It seems to me their usage are not related, could someone please explain?
Code becomes asynchronous on await - we wouldn't know what to return
What await does in addition to waiting for the promise to resolve is that it immediately returns the code execution to the caller. All code inside the function after await is asynchronous.
async is syntatic sugar for returning a promise.
If you don't want to return a promise at await, what would be the sane alternative in an asynchronous code?
Let's look at the following erroneous code to see the problem of the return value:
function f() {
// Execution becomes asynchronous after the next line, what do we want to return to the caller?
let result = await myPromise;
// No point returning string in async code since the caller has already moved forward.
return "function finished";
}
We could instead ask another question: why don't we have a synchronous version of await that wouldn't change the code to asynchronous?
My take on that is that for many good reasons making asynchronous code synchronous has been made difficult by design. For example, it would make it too easy for people to accidentally make their whole application to freeze when waiting for an asynchronous function to return.
To further illustrate the runtime order with async and await:
async function f() {
for(var i = 0; i < 1000000; i++); // create some synchronous delay
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
console.log("message inside f before returning, still synchronous, i = " + i);
// let's await and at the same time return the promise to the caller
let result = await promise;
console.log("message inside f after await, asynchronous now");
console.log(result); // "done!"
return "function finished";
}
let myresult = f();
console.log("message outside f, immediately after calling f");
The console log output is:
message inside f before returning, still synchronous, i = 1000000
message message outside f, immediately after calling f
message inside f after await, asynchronous now
done!
async and await are both meta keywords that allow asynchronous code to be written in a way that looks synchronous. An async function tells the compiler ahead of time that the function will be returning a Promise and will not have a value resolved right away. To use await and not block the thread async must be used.
async function f() {
return await fetch('/api/endpoint');
}
is equivalent to
function f() {
return new Promise((resolve,reject) => {
return fetch('/api/endpoint')
.then(resolve);
});
}