This question already has answers here:
Correct way to write a non-blocking function in Node.js
(2 answers)
Closed 1 year ago.
Could someone try and help me to understand why the first function is non-blocking while the second one blocks the rest of the code? Isn't Promise.resolve the same as resolving from a new Promise? I can't quite wrap my head around it.
function blockingCode() {
return new Promise((resolve, reject) => {
for (let i = 0; i < 2500000000; i++) {
// Doing nothing...
}
resolve('ping');
});
}
function nonBlockingCode() {
return Promise.resolve().then(() => {
for (let i = 0; i < 2500000000; i++) {
// Doing nothing...
}
return 'pong';
});
}
console.time('non-blocking');
nonBlockingCode().then((message) => console.log(message));
console.timeEnd('non-blocking');
// console.time('blocking');
// blockingCode().then((message) => console.log(message));
// console.timeEnd('blocking');
The two functions are actually blocking.
You have the illusion that the second one isn't blocking because calling Promise.resolve().then() adds one more round to the event loop, so console.timeEnd('non-blocking'); is reached before the code inside your promise even starts.
You will notice that both function block if you fix your code like this:
console.time('non-blocking');
nonBlockingCode()
.then((message) => console.log(message))
.then(() => console.timeEnd('non-blocking'));
Note that a promise is intended not to block when the time-consuming logic inside the promise is delegated to a third-party, and you just wait for the result (e.g. when a client does a call to a remote database, a remote web server, etc.).
If you are having a hard time with promises and then logic, have a look at the async / await syntax, I find it much easier to understand.
Related
This question already has answers here:
Aren't promises just callbacks?
(11 answers)
Closed 29 days ago.
I'm just discovering Promises and I'm trying to wrap my head around them. The W3C website has a page dedicated to it, featuring the following code :
let myPromise = new Promise(function(myResolve, myReject) {
let x = 0;
// The producing code (this may take some time)
if (x == 0) {
myResolve("OK");
} else {
myReject("Error");
}
});
myPromise.then(
function(value) {myDisplayer(value);},
function(error) {myDisplayer(error);}
);
I tried to make my own try at it, with the following code :
let p = new Promise(function test(resolve, reject){
// here is supposed to be where the async code takes place, according to the
// article.
let a = 0;
setTimeout(() => {a = Math.floor(Math.random()*6)}, "1000")
// ...however the condition triggers before the setTimeout takes place.
if(a >= 0) {
resolve(`Success ! a = ${a}`);
} else {
reject(`Failure ! a = ${a}`);
}
});
p.then(function logResult(result){
console.log(result);
})
So I figured that this should work :
let q = new Promise(function test(resolve, reject){
let a = 0;
setTimeout(() => {
a = Math.floor(Math.random()*6);
if(a >= 4) {
resolve(`Success ! a = ${a}`);
} else {
reject(`Failure ! a = ${a}`);
}
}, "1000")
});
q.then(function logResult(result){
console.log(result);
})
And it does work, but it's the setTimeout callbacks that handles everything, not the promise itself, and doing it without the promise works just as fine :
let a = 0;
setTimeout(() => {
a = Math.floor(Math.random() * 6);
if (a >= 4) {
console.log(`Success ! a = ${a}`);
} else {
console.log(`Failure ! a = ${a}`);
}
}, "1000")
So there's definitely something I don't understand about how Promises are supposed to handle async code or why they're useful altogether. I wish someone would explain it to me.
The whole point of promises is to allow some other code to be executed while waiting for a promise to resolve or reject.
In your code, however, no action takes time; therefore, you can do the same without promises.
The most common scenario for promises is something like this:
Show the user a progress dialog
Request some data from the backend
Once data is retrieved, process it
After data is processed, show it to a user
There will be a delay between steps 2 and 3 because an HTTP request will take some time naturally. Also, step 3 may take some time to process, and we don't want to block our code execution while waiting for it to complete. In this case, we wrap step 2 in a promise and use then to execute steps 3 and 4.
Please let me know if this helps.
Promises are used to handle operations which take longer than others. For example fetching something from a server. Since JavaScript is single-threaded, promises and callbacks are the answer for problems with long executing operations. If you would fetch something from a server synchronously (without a promise or callback), you wouldn't be capable to interact with your app in any other way (Click handlers wouldn't work.). It would block the main thread for the time when it fetches the data. Promises and callbacks are executing when there is nothing left to execute. Using promise to wrap callback function might be used to utilize async/await and .then() with it. It's in addition to prevent what's called - callback hell (a lot of callbacks nested in each other).
I'm doing some unit testing. The test framework loads a page into an iFrame and then runs assertions against that page. Before each test begins, I create a Promise which sets the iFrame's onload event to call resolve(), sets the iFrame's src, and returns the promise.
So, I can just call loadUrl(url).then(myFunc), and it will wait for the page to load before executing whatever myFunc is.
I use this sort of pattern all over the place in my tests (not just for loading URLs), primarily in order to allow changes to the DOM to happen (e.g. mimick clicking a button, and wait for divs to hide and show).
The downside to this design is that I'm constantly writing anonymous functions with a few lines of code in them. Further, while I have a work-around (QUnit's assert.async()), the test function that defines the promises completes before the promise is run.
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.
In essence, is there a way to get the following to spit out results in the correct order?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
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.
If using ES2016 you can use async and await and do something like:
(async () => {
const data = await fetch(url)
myFunc(data)
}())
If using ES2015 you can use Generators. If you don't like the syntax you can abstract it away using an async utility function as explained here.
If using ES5 you'll probably want a library like Bluebird to give you more control.
Finally, if your runtime supports ES2015 already execution order may be preserved with parallelism using Fetch Injection.
Another option is to use Promise.all to wait for an array of promises to resolve and then act on those.
Code below shows how to wait for all the promises to resolve and then deal with the results once they are all ready (as that seemed to be the objective of the question); Also for illustrative purposes, it shows output during execution (end finishes before middle).
function append_output(suffix, value) {
$("#output_"+suffix).append(value)
}
function kickOff() {
let start = new Promise((resolve, reject) => {
append_output("now", "start")
resolve("start")
})
let middle = new Promise((resolve, reject) => {
setTimeout(() => {
append_output("now", " middle")
resolve(" middle")
}, 1000)
})
let end = new Promise((resolve, reject) => {
append_output("now", " end")
resolve(" end")
})
Promise.all([start, middle, end]).then(results => {
results.forEach(
result => append_output("later", result))
})
}
kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated during execution: <div id="output_now"></div>
Updated after all have completed: <div id="output_later"></div>
This question already has answers here:
async/await implicitly returns promise?
(5 answers)
Closed 2 years ago.
I have an API call to an array of links and I want to use a map function to save al the responses
const allImages = list.map(async (imageLink) => {
const image = await axios.get(imageLink);
return image.data.primaryImage;
});
Why allImages is still an array of promises and not an array of responses?
Because Array.map method itself is not an async method. In fact, I must remember you that JavaScript is a single threaded language. The only operations that can really happen simultaneously are I/O operations handled by your platform.
With that being said, in your case, Array.map will loop through your whole array and will return a new array containing the returned values from your callback for each original item.
An Async function always immediately and implicitly returns a promise that will then be resolved to the explicitly returned value of your function.
That is why you get an array of promises.
What you can do then, if you want to use the responses, is something like this:
const allImages = list.map(async (imageLink) => {
const image = await axios.get(imageLink);
return image.data.primaryImage;
});
Promise.all(allImages).then((responses) => {
console.log(responses); // THIS ARE THE RESPONSES YOU ARE LOOKING FOR.
});
Please let me know if you have any other doubt.
In response to comments:
JS code execution can never be paused, it would freeze your engine and would break the entire purpose of JS async implementation.
When you are inside an async function and find an await statement, code execution 'jumps' outside of the async scope 'promising' to resume where it left as soon as the Promise related to the await statement is fulfilled.
JS async/await is just syntactic sugar to deal with promises. And promises are just syntactic sugar to deal with callbacks.
See the following example using your code:
let count = 0;
const allImages = list.map(async (imageLink) => {
const image = await axios.get(imageLink);
// CODE EXECUTION 'STOPS' HERE, BUT CONTINUES OUTSIDE OF THE ASYNC SCOPE. Array.map PASSES TO NEXT ITEM.
count++;
console.log('A' + count);
return image.data.primaryImage; // THIS RESOLVES THE PROMISE.
});
// CODE EXECUTION CONTINUES
console.log('B');
Promise.all(allImages).then(() => {
// ALL PROMISES HAVE BEEN FULFILLED.
console.log('C');
});
/*
EXPECTED OUTPUT ORDER:
B
A1, A2, A3... (depending on http responses arrival order)
C
*/
Hopefully a more intuitive example that should work as you expect:
(async () => {
for (let i = 0; i < list.length; i++) {
const imageLink = list[i];
const image = await axios.get(imageLink);
// CODE EXECUTION 'STOPS' HERE.
list[i] image.data.primaryImage;
}
console.log(list); // AN ARRAY OF RESPONSES.
})();
// HOWEVER, CODE EXECUTION NEVER REALLY STOPS AND CONTINUES HERE. OUTSIDE OF THE async SCOPE.
Synchronicity in js loops is still driving me up the wall.
What I want to do is fairly simple
async doAllTheThings(data, array) {
await array.forEach(entry => {
let val = //some algorithm using entry keys
let subVal = someFunc(/*more entry keys*/)
data[entry.Namekey] = `${val}/${subVal}`;
});
return data; //after data is modified
}
But I can't tell if that's actually safe or not. I simply don't like the simple loop pattern
for (i=0; i<arrayLength; i++) {
//do things
if (i === arrayLength-1) {
return
}
}
I wanted a better way to do it, but I can't tell if what I'm trying is working safely or not, or I simply haven't hit a data pattern that will trigger the race condition.
Or perhaps I'm overthinking it. The algorithm in the array consists solely of some MATH and assignment statements...and a small function call that itself also consists solely of more MATH and assignment statements. Those are supposedly fully synchronous across the board. But loops are weird sometimes.
The Question
Can you use await in that manner, outside the loop itself, to trigger the code to wait for the loop to complete? Or is the only safe way to accomplish this the older manner of simply checking where you are in the loop, and not returning until you hit the end, manually.
One of the best ways to handle async and loops is to put then on a promise and wait for Promise.all remember that await returns a Promise so you can do:
async function doAllTheThings(array) {
const promises = []
array.forEach((entry, index) => {
promises.push(new Promise((resolve) => {
setTimeout(() => resolve(entry + 1), 200 )
}))
});
return Promise.all(promises)
}
async function main () {
const arrayPlus1 = await doAllTheThings([1,2,3,4,5])
console.log(arrayPlus1.join(', '))
}
main().then(() => {
console.log('Done the async')
}).catch((err) => console.log(err))
Another option is to use generators but they are a little bit more complex so if you can just save your promises and wait for then that is an easier approach.
About the question at the end:
Can you use await in that manner, outside the loop itself, to trigger the code to wait for the loop to complete? Or is the only safe way to accomplish this the older manner of simply checking where you are in the loop, and not returning until you hit the end, manually.
All javascript loops are synchronous so the next line will wait for the loop to execute.
If you need to do some async code in loop a good approach is the promise approach above.
Another approach for async loops specially if you have to "pause" or get info from outside the loop is the iterator/generator approach.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
(function() {
function main() {
call1();
call2();
}
function call1() {
return new Promise(() => {
for (let i=0; i<100; i++) {
console.log('This is call-1:', i);
}
});
}
function call2() {
return new Promise(() => {
for (let i=0; i<100; i++) {
console.log('This is call-2:', i);
}
});
}
main();
})();
http://plnkr.co/edit/NtioG92Tiba1KuKTx24I
The output contains all call-1 statements followed by all call-2 statements. I want to run those 2 calls in parallel. This is just an example to mimic my real code where I have 2 functions with ajax calls inside each function. success or failure of those calls with trigger another series of calls. So, I want to those 2 main functions in parallel. Is this the right approach?
This is a rather common misconception about Promises. The Promise constructor (or rather, the function you pass to it) is executed synchronously and immediately.
The following code:
console.log(1);
new Promise(resolve => resolve(console.log(2));
console.log(3);
Outputs 1 2 3 in that order, always.
Both of the functions you've passed to both of your Promise constructors are fully synchronous. There's no asynchronous action (like a setTimeout, or reading a file with a callback), so it's executed one, after the other.
Unlike what some of the other answers may tell you, Promise.all() will not save you in this case. The event loop, or ticks, or any other the other terms you might have heard of do not come into effect. Your code is fully synchronous.
Most JavaScript runtimes (browsers, Node.js, etc) are single threaded, in that your JavaScript code runs in a single thread (the browser uses many threads, but your JS code runs in one).
So in this particular case, there's nothing you can do (save from using workers or other threading options, which you probably don't want to get into). You can't magically make synchronous code asynchronous, even with trickery.
Look into Promise.all https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all.
This will call all your promises and resolve when they are complete (resolved or rejected).
Another option, depending on your use case, is Promise.race.
This will return the first Promise that completes (resolves or rejects) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
I believe you want to run your main function like this:
function main() {
Promise.all([call1(), call2()])
.then( (data) => {
// this block will run, if and when BOTH calls/promises resolve
// process the data from calls
})
.catch( (err) => { // process the err });
}
Promise.all is way of how to run 2 and more async calls and wait until ALL of them are completed. As mentioned in comments they are not running parallel as you might think.
Also make sure, that your call1() and call2() function will call resolve or reject functions at some point. By calling these functions you let program know whether it is completed or "errored". More about it here
Actually your two Promise run in same thread.
So you may want Using Web Workers.
Web Workers is a simple means for web content to run scripts in
background threads. The worker thread can perform tasks without
interfering with the user interface. In addition, they can perform I/O
using XMLHttpRequest (although the responseXML and channel attributes
are always null)
Like below demo:
let url1 = window.URL.createObjectURL(
new Blob([document.querySelector('#worker1').textContent])
)
let worker1 = new Worker(url1)
let url2 = window.URL.createObjectURL(
new Blob([document.querySelector('#worker2').textContent])
)
let worker2 = new Worker(url2)
worker1.onmessage = (msg)=>{
console.log(msg.data)
}
worker2.onmessage = (msg)=>{
console.log(msg.data)
}
worker1.postMessage('init');
worker2.postMessage('init');
<script id="worker1" type="app/worker">
addEventListener('message', function () {
for (let i=0; i<100; i++) {
postMessage('This is call-1: ' + i)
}
}, false);
</script>
<script id="worker2" type="app/worker">
addEventListener('message', function () {
for (let i=0; i<100; i++) {
postMessage('This is call-2: ' + i)
}
}, false);
</script>