How to Wait for a JavaScript Promise to Resolve Before Resuming Function

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, while promise.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



Leave a reply



Submit