How to wait for a JavaScript Promise to resolve before resuming function?
I'm wondering if there is any way to get a value from a Promise or
wait (block/sleep) until it has resolved, similar to .NET's
IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is
single-threaded, but I'm hoping that doesn't mean that a function
can't yield.
The current generation of Javascript in browsers does not have a wait()
or sleep()
that allows other things to run. So, you simply can't do what you're asking. Instead, it has async operations that will do their thing and then call you when they're done (as you've been using promises for).
Part of this is because of Javascript's single threadedness. If the single thread is spinning, then no other Javascript can execute until that spinning thread is done. ES6 introduces yield
and generators which will allow some cooperative tricks like that, but we're quite a ways from being able to use those in a wide swatch of installed browsers (they can be used in some server-side development where you control the JS engine that is being used).
Careful management of promise-based code can control the order of execution for many async operations.
I'm not sure I understand exactly what order you're trying to achieve in your code, but you could do something like this using your existing kickOff()
function, and then attaching a .then()
handler to it after calling it:
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}
kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});
This will return output in a guaranteed order - like this:
start
middle
end
Update in 2018 (three years after this answer was written):
If you either transpile your code or run your code in an environment that supports ES7 features such as async
and await
, you can now use await
to make your code "appear" to wait for the result of a promise. It is still programming with promises. It does still not block all of Javascript, but it does allow you to write sequential operations in a friendlier syntax.
Instead of the ES6 way of doing things:
someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});
You can do this:
// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}
wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});
async
functions return a promise as soon as the first await
is hit inside their function body so to the caller an async function is still non-blocking and the caller must still deal with a returned promise and get the result from that promise. But, inside the async
function, you can write more sequential-like code using await
on promises. Keep in mind that await
only does something useful if you await a promise so in order to use async/await
, your asynchronous operations must all be promise-based.
Wait for a promise to be resolved before continuing with function
It depends on how your grouping your data but this is a simple example. async
functions return a promise so you need to await them too.
const { body } = document;
async function takeScreenshot() {
const screenshot = await html2canvas(body);
return screenshot.toDataURL();
}
async function main() {
const canvas = await takeScreenshot();
body.appendChild(canvas);
}
main();
How to execute code while waiting for a promise to resolve?
Instead of awaiting the call to send
, assign the call to an outside variable, and then await
it after calling calculate
in the next iteration.
var arrayToSend = [1, 2, 3, 4, 5, 6, 7, 8, 9]
function send(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
console.log('sent ' + x)
}, 1000)
})
}
function calculate(x) {
return x ** 2
}
async function loopAndSendArray() {
let lastSend;
for (const val of arrayToSend) {
const calculatedVal = calculate(val);
await lastSend;
lastSend = send(calculatedVal)
}
await lastSend;
}
loopAndSendArray();
How to wait for a promise to resolve before the next iteration in for loop
It's hard to understand the first time, but here I go.
The simple answer is "You can't do that", javascript works with an 'event loop', it's like a thread containing all the tasks javascript is going to do, when you use an asynchronous task like 'search' it escapes the 'event loop' for being asynchronous . But the 'for loop' is not asynchronous so it will be processed in the 'Event Loop'.
This means that 'fetch' will exit the 'Event Loop' and when its request is completed it will return to the 'Event Loop', in this moment, the 'for loop' was terminate.
But don't worry, you can solve it, how? well, you can iterate the loop and save a new array of promise, await for all of them will complete and in this moment create your 'tr' row
Its an example with your code:
The first function could be like this:
const promises = [];
fetch(url)
.then(resp => resp.json())
.then((item) => {
const list = item;
for (let i in list) {
promises.push(getCustomer(list[i].customer_id))
}
Promise.all(promises).then((resolveAllData) => {
//Do all that you need with your data
//Maybe you can use a for loop for iterate 'responseAllData
});
}).catch((err) => {
//manage your err
})
And the second function could be like this:
function getCustomer(customer_id) {
return new Promise((resolve, reject) => {
const url = 'http://127.0.0.1:8000/user-detail/' + customer_id + '/';
fetch(url)
.then(resp => resp.json())
.then((item) => resolve(item))
.catch((err) => {
//manage your err
reject(err)
})
})
}
A recommendation, learn how JavaScript works and its asynchronism, try not to use 'var', to get better performance and have no problems with scope
wait for loop to finish populating array before executing next function
You can modify your code like this
imgArray is a promise so you cannot access the resolved value directly
var nextBtn = document.querySelector('[aria-label="Next"]')
const imgArray = Promise.all(Array(15).fill(0).map((_, i) => new Promise(resolve => {
let array = []
setTimeout(() => {
if (nextBtn) {
array = Object.values(document.querySelectorAll('img')).map(img => img.src);
nextBtn.click();
nextBtn = document.querySelector('[aria-label="Next"]');
};
resolve(array)
}, i * 1000);
}))).then(data => [...new Set(data.flat())])
imgArray.then(d => console.log(d)) // expected: [], needed: [element1, element2, ...]
Why does this promise resolve when I am not awaiting it
As other posts/comments said, later(1000)
is evaluated right away and don't wait for your await Promise.all
call to run the promise code.
you could achieve that by doing the following:
const promises = [() => later(1000)];
function later(delay:number) {
return new Promise<void>(function(resolve) {
setTimeout(() => {
console.log('test');
resolve();
}, delay);
});
}
await Promise.all(promises.map(f => f()));
Javascript promise not waiting to resolve before then
Per Why await beats Promise.then(...)"
The fundamental difference between await and vanilla promises is that
await X()
suspends execution of the current function, whilepromise.then(X)
continues execution of the current function after adding the X call to the callback chain.
Asynchronous file reading, cannot make function finish before returning
You need to use the non-callback version of fs.readFile
in order to actually await
reading the file. Also using .map
does not make a lot of sense as you're not actually mapping something, so simply use a for .. of
loop:
for (const file of allFiles){
try {
const data = await fs.promises.readFile(file);
// ...
} catch(err) {
// handle error
}
}
console.log('this should be last');
Related Topics
Which Characters Are Valid/Invalid in a JSON Key Name
Replace a Regex Capture Group with Uppercase in JavaScript
How to Delete Document from Firestore Using Where Clause
How to Scrape Pages with Dynamic Content Using Node.Js
JavaScript Syntax (0, Fn)(Args)
Keyword 'Const' Does Not Make the Value Immutable. What Does It Mean
Keys in JavaScript Objects Can Only Be Strings
How to Find JavaScript Variable by Its Name
How to Create Every Combination Possible for the Contents of Two Arrays
JavaScript Extract Certain Properties from All Objects in Array
Http Status Code 401 Even Though I'm Sending Credentials in the Request
Why Is It Object.Defineproperty() Rather Than This.Defineproperty() (For Objects)
Asynchronous Operations in Constructor
How to Sequentially Run Promises with Q in JavaScript
What Does Three Dots Do in Reactjs
"Invocation Context" and "Execution Context" in JavaScript: Are We Talking of the Same Thing
Export JavaScript Data to CSV File Without Server Interaction