Is the map method parallel? [duplicate] - javascript

This question already has answers here:
How is Javascript single threaded?
(6 answers)
Closed 2 years ago.
Is the method [1, 2, 3].map(item=>f(item)) execute f(1), f(2), f(3) parallelly? Or execute like "f(1), then f(2), then f(3)"?

Actually it execute "f(1), then f(2), then f(3)"?
Because JS is single-threaded. So if the f function is an async task (setTimeout, Ajax call, etc..), then it can be scheduled to waits parallelly combined with promise.all. Otherwise, it still has to execute synchronously.
One more thing to keep in mind is when you use await inside async function,
It does only waits parallel when you use promise.all.
var tick;
const log = (v) => console.log(`${v} \n Elapsed: ${Date.now() - tick}`);
const f = (number) => new Promise(resolve => {
setTimeout(() => log(number), 1000);
});
async function Run(){
tick = Date.now();
await Promise.all([f(1), f(2), f(3)]);
}
function Run_2(){
tick = Date.now();
[f(1), f(2), f(3)];
}
Run();
Run_2();
While you await each f, it takes 3s in total.
var tick;
const log = (v) => console.log(`${v} \n Elapsed: ${Date.now() - tick}`);
const f = (number) => new Promise(resolve => {
setTimeout(() => resolve(number), 1000);
});
async function Run(){
tick = Date.now();
let a = await f(1);
let b = await f(2);
let c = await f(3);
log([a, b, c]);
}
Run();
However, Promise.all can only waits async tasks in parallel. It can't convert a synchronous CPU block code into a separate thread or anything.

Related

ES6 variable scopes in loops with await inside

As we may know, var keyword defines a variable globally, or locally to an entire function regardless of block scope. So the below code will log 5 times with the same value.
for(var i = 0; i < 5; i++){
setTimeout(() => console.log(i), 2000);
}
To visualize the above JS runtime like this
As you can see, 5 tasks in Callback Queue will wait until Call stack is empty. So after the synchronous loop is done - It means Call stack is empty in my case, then 5 scheduled tasks - console.log(i) with the value of i is equal to 5 will be executed. You can play around here
And what I want is to log right after i == 2. It works as I expected.
var sleep = (ms) => new Promise(resolve => setTimeout(() => resolve(1), ms));
async function runAsync(){
for(var i = 0; i < 5; i++){
if(i == 2) await sleep(2000);
setTimeout(() => console.log(i));
}
}
runAsync();
But I'm curious how it works while I'm not sure the call stack is empty? Whether when I'm using await, allowing the caller of the async function to resume execution, or some else?
Any explanation/visualization of image flow would be appreciated. Thanks.
await cedes control of the thread and allows other processes to run until the promise being awaited resolves. Even if the promise is already resolved, await will yield to any "microtasks" that have been waiting to execute, but that's a moot point in your case because your promise takes a full two seconds to resolve.
In your case, two setTimeouts are queued up before the await, so they are allowed to run when the await happens.
The timeline is basically like this:
i = 0
setTimeout 1 scheduled
i = 1
setTimeout 2 scheduled
i = 2
await
setTimeout 1 callback runs
setTimeout 2 callback runs
setTimeout 3 scheduled
i = 3
setTimeout 4 scheduled
i = 4
setTimeout 5 scheduled
i = 5
loop ends
setTimeout 3 callback runs
setTimeout 4 callback runs
setTimeout 5 callback runs
You can see that i is 2 when the first pair of setTimeouts are allowed to execute, and it is 5 when the remaining 3 execute.
Here is a snippet that hopefully demonstrates the process a little better:
var sleep = (ms) => new Promise(resolve => setTimeout(() => resolve(1), ms));
async function runAsync() {
for (var i = 0; i < 5; i++) {
console.log('i is now', i);
if (i == 2) {
console.log('about to sleep');
await sleep(5000);
console.log('now done sleeping');
}
console.log('about to setTimeout. i is', i, 'right now');
setTimeout(() => {
console.log('setTimeout task running:', i, '- scheduling a new timeout.');
setTimeout(() => console.log('inner timeout:', i), 1000);
});
}
console.log('done looping. i is', i);
}
runAsync();

Javascript - correct way to wait for super long loop?

Maybe this is an async / await situation but I thought async was mainly for api calls(?)
How do you wait a long loop to finish, like this:
let x;
for (i = 1, i < 10000000000000000, i++) {
x += (i * 99999);
}
console.log(x);
I thought async was mainly for api calls(?)
There are two different concepts related to the async word:
async/await functions
Syntax sugar for receive Promises results in syncronous manner
real asynchronous behavior
XHR api calls, delayed execution, event handling
async/await function does not make your function execution asynchronous automagically.
const foo = async (i) => { console.log('foo running', i); return i == 0 ? 42 : await foo(i-1); };
console.log('foo before')
foo(5)
.then(x => console.log('foo', x))
console.log('foo after')
// foo before
// foo running 5
// foo running 4
// foo running 3
// foo running 2
// foo running 1
// foo running 0
// foo after
// foo 42
Javascript is one-threaded, all concurrent tasks must be splitted into async chunks to have any chance to other to work.
So, you should split your sync loop to many async parts to not to be frozen.
For example(I reduce params to have not too much time for wait):
async function calcX() {
let x = 0;
function iteration(i) {
x += (i * 99999);
if (++i >= 10000) return Promise.resolve(x);
return new Promise((resolve) => {
setTimeout(() => iteration(i).then(resolve), 0);
// or requestAnimationFrame
});
}
return await iteration(1);
}
const start = Date.now();
calcX()
.then(x => console.log(x, Date.now() - start), err => console.error(err));
// 4999450005000 42465
It can be too slow if you put each iteration to event loop. So you can optimize it by batching of them(see #Steve's answer)
Or use WebWorker for your heavy sync task
You can convert long running synchronous functions into asynchronous functions by checking to see if a set amount of time has elapsed, and then coming back to the function later (achieved in this example via setTimeout):
var lastBreak = Date.now()
function takeABreak() {
return new Promise(resolve=>setTimeout(resolve));
}
async function maybeTakeABreak() {
if (Date.now() - 17 > lastBreak) {
lastBreak = Date.now();
await takeABreak();
}
}
async function myLongLoop() {
let x = 0;
for (let i = 1; i < 100000000000000; i++) {
await maybeTakeABreak();
x += (i * 99999);
if (!(i%1000000)) {
console.log(i);
// alternatively you could run `await takeABreak();` here
}
}
return x;
}
myLongLoop().then(x=>console.log(x));

Promise.all inside an asynchronous function [duplicate]

This question already has answers here:
Any difference between await Promise.all() and multiple await?
(6 answers)
Closed 3 years ago.
I have 2 codes
1 code
async function foo() {
const result1 = asyncFunc1();
const result2 = asyncFunc2();
return [result1, result2];
}
2 code
async function foo() {
const [result1, result2] = await Promise.all([
asyncFunc1(),
asyncFunc2(),
]);
return [result1,result2];
}
question
Is there any difference between the two?
As the comments state, you did not await the function calls in the first snippet, so you will get promises as return values. However if you used await, one major difference is that in the first snippet, asyncFunc2 isn't executed until asyncFunc1 is resolved (assuming you use await). Whereas, in the second snippet, asyncFunc2 is executed right after asyncFunc1 regardless of whether it has resolved.
Promise.all will return the results in the order in which you pass the functions.
See docs for Promise.All and Await
As per the comments, there is essentially no difference in the two, other than the fact that you have not awaited the results from the two async functions, so you're gonna end up with just the promise objects. Async functions don't await scoped promises / async code automatically, they just allow you to use the await keyword, which is just stopping the execution until the underlying promise is resolved.
Here's an attempt to illustrate those differences.
What's important to note is that the returned values for the first function are not 1, 2 as would be expected.
const asyncFunc = (a) => {
return new Promise((resolve) => {
setTimeout(() => resolve(a), 1000);
})
}
const asyncFunc1 = () => asyncFunc(1);
const asyncFunc2 = () => asyncFunc(2);
async function foo() {
const result1 = asyncFunc1();
const result2 = asyncFunc2();
return JSON.stringify({ result1, result2 });
}
async function foo2() {
return [result1, result2] = await Promise.all([
asyncFunc1(),
asyncFunc2(),
]);
}
(async () =>{
const el = document.createElement('div');
el.appendChild(document.createTextNode(await foo()));
el.appendChild(document.createTextNode(await foo2()));
document.querySelector('body').appendChild(el);
})();
// {"result1":{},"result2":{}} 1,2
Here's a fiddle to play around with; jsfiddle.
Just find it out! Here is a snippet that shows all major differences:
const timer = ms => new Promise(res => setTimeout(res, ms));
async function one() {
console.log("1 one called");
await timer(2000);
console.log("1 one done");
}
async function two() {
console.log("2 two called");
await timer(1000);
console.log("2 two done");
// throw new Error; // Uncomment to see another interesting behaviour
}
(async function main() {
const startParallel = Date.now();
await Promise.all([one(), two()]);
console.log(`parallel done, took ${Date.now() - startParallel}`);
const startSerial = Date.now();
await one();
await two();
console.log(`serial done, took ${Date.now() - startSerial}`);
})();

Using RxJS how to buffer function calls until an other async function call has resolved

How can I use RxJS to buffer function calls until another async function has resolved?
Here is a simple example of what I'd like to accomplish
function asyncFunc(time) {
setTimeout(() => {
console.log('asyncFunc has resolved');
}, time);
}
function funcToBuffer(time) {
setTimeout(() => {
console.log(time);
}, time);
}
asyncFunc(3000);
funcToBuffer(1000);
funcToBuffer(2000);
funcToBuffer(4000);
funcToBuffer(5000);
asyncFunc(8000);
funcToBuffer(6000);
funcToBuffer(7000);
At the moment this code will print:
1000
2000
asyncFunc has resolved
4000
5000
6000
7000
asyncFunc has resolved
What I want is for this to print:
asyncFunc has resolved
1000
2000
4000
5000
asyncFunc has resolved
6000
7000
In essence, I want some kind of control flow that allows me to call funcToBuffer whenever I feel like, but under the hood, I want it to hold on executing whenever asyncFunc is executing and waiting to be resolved. Once asyncFunc has resolved, funcToBuffer calls should no longer be buffered and be executed right away.
I have tried playing with the buffer operator but I wasn't able to achieve the desired outcome.
If I understand it right, your main goal is to control the execution of a sequence of functions through a mechanism that buffers them until something happens, and that something is exactly what triggers the execution of the functions buffered.
If this is correct, the following could be the basis for a possible solution to your problem
const functions$ = new Subject<() => any>();
const buffer$ = new Subject<any>();
const executeBuffer$ = new Subject<any>();
const setBuffer = (executionDelay: number) => {
buffer$.next();
setTimeout(() => {
executeBuffer$.next();
}, executionDelay);
}
const functionBuffer$ = functions$
.pipe(
bufferWhen(() => buffer$),
);
zip(functionBuffer$, executeBuffer$)
.pipe(
tap(functionsAndExecuteSignal => functionsAndExecuteSignal[0].forEach(f => f()))
)
.subscribe();
Let me explain a bit the code.
First thing, we build functions$, i.e. an Observable of the functions we want to control. The Observable is built using a Subject, since we want to be able to control the notification of such Observable programmatically. In other words, rather than kicking the execution of a function like this funcToBuffer(1000), we create the function (as an object) and ask the functions$ Observable to emit the function like this
const aFunction = () => setTimeout(() => {console.log('I am a function that completes in 1 second');}, 1000);
functions$.next(aFunction);
In this way we have created a stream of functions that eventually will be executed.
Second thing, we create 2 more Observables, buffer$ and executeBuffer$, again using Subjects. Such Observables are used to signal when we have to create a buffer out of the functions emitted so far by functions$ and when we have to start the execution of the functions buffered.
These last 2 Observables are used in the function setBuffer. When you call setBuffer you basically say: please, create a buffer with all the functions which have been emitted so far by functions$ and start executing them after the executionDelay time specified as parameter.
The buffering part is performed by the functionBuffer$ Observable which is created using bufferWhen operator. The execution part is implemented leveraging the zip operator, that allows us to set the rhythm of execution of the functions based on the emissions of executeBuffer$ Observable.
You can test the above code setting up the following test data.
let f: () => any;
setBuffer(3000);
f = () => setTimeout(() => {console.log('f1');}, 1000);
functions$.next(f);
f = () => setTimeout(() => {console.log('f2');}, 2000);
functions$.next(f);
f = () => setTimeout(() => {console.log('f4');}, 4000);
functions$.next(f);
f = () => setTimeout(() => {console.log('f5');}, 5000);
functions$.next(f);
setBuffer(8000);
f = () => setTimeout(() => {console.log('f6');}, 6000);
functions$.next(f);
f = () => setTimeout(() => {console.log('f7');}, 7000);
functions$.next(f);
setBuffer(16000);
I started working on a solution with combineLatest but figured that a BehaviorSubject would be a better solution once I put more thought into it.
const { BehaviorSubject } = rxjs;
const { filter } = rxjs.operators;
let finalised$ = new BehaviorSubject(false);
function asyncFunc(time) {
setTimeout(() => {
console.log('asyncFunc has resolved');
if (!finalised$.getValue()) {
finalised$.next(true);
}
}, time);
}
function funcToBuffer(time) {
finalised$.pipe(filter(finalised => finalised)).subscribe(_ => { // Filter so only fire finalised being true
setTimeout(() => {
console.log(time);
}, time);
});
}
asyncFunc(3000);
funcToBuffer(1000);
funcToBuffer(2000);
funcToBuffer(4000);
funcToBuffer(5000);
asyncFunc(8000);
funcToBuffer(6000);
funcToBuffer(7000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.2/rxjs.umd.min.js"></script>
CombineLatest that waits for both obsevables to fire.
const { of, combineLatest } = rxjs;
const { delay } = rxjs.operators;
let obs1$ = of(1).pipe(delay(1000));
let obs2$ = of(2).pipe(delay(2000));
let now = new Date();
combineLatest(obs1$, obs2$).subscribe(([obs1, obs2]) => {
let ellapsed = new Date().getTime() - now.getTime();
console.log(`${obs1} - ${obs2} took ${ellapsed}`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.2/rxjs.umd.min.js"></script>

How to write async code in JS?

JavaScript is single thread language, which means all user-written code will run in the main thread. For example, in Node.js, the async IO read is an async operation, it runs in a worker thread, but the callback which developer has written run in the main thread as other JS code. So if I identify one JS function with async, it actually did not run in other thread, more important, an async also doesn't mean non-blocking.
const sleep = (wait) => {
const start = new Date().getTime();
while (new Date().getTime() - start <= wait) {}
}
const async_print1 = async () => {
setTimeout(() => {
sleep(2000);
console.log('async_print1'); /// in 4s.
}, 2000);
}
const async_print2 = async () => {
setTimeout(() => {
sleep(1000);
console.log('async_print2'); /// in 5s.
}, 2000);
}
const sync_print = () => {
sleep(1000);
console.log('sync_print'); /// in 1s.
}
async_print1();
async_print2();
sync_print();
The output:
[00:00] <program start>
[00:01] sync_print
[00:04] async_print1
[00:05] async_print2
[00:05] <over>
Fisrt, sync_print run in main thread, it sleep 1s then print. Then, two timer start, after 2s, run loop need call two callback, the two callback both run in main thread, so they're blocking operations.
My question is how to make two sleep() run in other thread? Or just can not?
**Updated my question **
Sorry for my poor english and expression, I finally understand. Thanks you. Is it possible to execute Javascript functions with multi-threads
There is no way to turn synchronous code into asynchronous code. If the event loop is busy running your while loop (which is blocking code), then it is going to be too busy to do anything else. The async keyword just makes a function return a promise (and allows you to use await inside it).
You can shunt code off into another thread using Web Workers.
You probably don't need web workers yet. It looks like you forgot await altogether -
const sleep = ms =>
new Promise (r => setTimeout (r, ms))
const asyncPrint1 = async () =>
{ await sleep (2000)
console.log ("async print 1")
}
const asyncPrint2 = async () =>
{ await sleep (2000)
console.log ("async print 2")
}
const syncPrint = () =>
{ console.log ("sync print")
}
const main = async () =>
{ await asyncPrint1 () // ...2 seconds
await asyncPrint2 () // ...4 seconds
await sleep (1000) // ...5 seconds
syncPrint ()
}
main ()
.then (console.log, console.error)
// async print 1
// async print 2
// sync print
Inside an async function, you can await as many other async calls as you want -
const sleep = ms =>
new Promise (r => setTimeout (r, ms))
const main = async () =>
{ console.log ("begin")
await sleep (1000)
console.log ("1 second has passed")
await sleep (1000)
await sleep (1000)
console.log ("3 seconds have passed")
await sleep (1000)
await sleep (1000)
await sleep (1000)
console.log ("6 seconds have passed")
}
main ()
.then (console.log, console.error)
// begin
// 1 second has passed
// 3 seconds have passed
// 6 seconds have passed
// undefined

Categories