2

I'm relatively new to Promises in Javascript, but have recently fell in love with their elegance, particularly in the Bluebird library.

This is probably a newbie question, but how could I convert a normally-synchronous function to run asynchronously? If I, for example, wanted to compute Math.random()*RANGE thirty times in-parallel, how exactly could I do that with promises (in either Q or Bluebird)?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Tombert
  • 530
  • 5
  • 13
  • 1
    If you want it to actually run asynchronously (so other code can run interwoven with its execution), you would either have to use `setTimeout()` to schedule consecutive chunks of execution or use `webWorkers` to actually set up another thread. You can see the core mechanism [here](http://stackoverflow.com/questions/10344498/best-way-to-iterate-over-an-array-without-blocking-the-ui/10344560#10344560) for executing chunks of work with `setTimeout()` which could then just return a promise and then resolve that promise when the work was done. – jfriend00 Jul 19 '14 at 01:00
  • 1
    I presume you also know that computing 30 random numbers takes very little time and doesn't really need to be dealt with in an async way and in fact may perform worse by adding overhead of doing it async - perhaps this is only an example you're using? – jfriend00 Jul 19 '14 at 02:16
  • @jfriend00 I was just using the Math.random as an example, but I like the idea of wrapping stuff in a `setTimeout(fn,0)` to force asynchonity. – Tombert Jul 19 '14 at 16:18
  • i think your question will receive much more responses if you would give another example (not Math.random): i have a NodeJS app with `Bluebird` promises and want to run 30 queries (let's say i have Redis, Postgres and S3 subsystems - and i need to run 10 queries in each). All queries are independent, and instead of waiting for `T1 + T2 + .. + T30` seconds, i want to wait for `max(T1, T2 .., T30) + small_overhead_of_parallelism`. So how can I achieve something like this with Bluebird API the most elegant way? – maxkoryukov Oct 27 '22 at 02:13

2 Answers2

2

You cannot. Promises don't "make code parallel", they just provide a better abstraction for asynchronous code - they don't have more power than callbacks.

A synchronous code will always be executed synchronously, and is - due to JavaScript's single-threaded nature - not parallelisable. Even if you give it a callback whose execution is deferred by the use of an actually async function, that will just defer the callback to a later event loop slice, but not make your synchronous task execute in parallel to anything else - and won't make it execute faster either. It only might help to break up long-running code into chunks (see here or here) which can make an app feel faster.

What you can do is execute the code on another thread (WebWorker, node cluster, …) and use events to pass the results back. For those events, you could code a nice promise abstraction; but seriously - the overhead of threads is much too large for just generating 30 random numbers.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    This is the correct answer. The key thing here is the difference between concurrency which means execution is interleaved and parallelism which means things run together. It's worth mentioning that everything in JavaScript is synchronous except host functions. – Benjamin Gruenbaum Jul 19 '14 at 08:02
  • I'm asking as the Async module for Node has a .parallel function, to run several functions in that. I guess what I'm asking is how to replicate that in promises. – Tombert Jul 19 '14 at 15:41
  • @Tombert: Notice that [async.parallel has the same implications](http://stackoverflow.com/q/21744724/1048572), and [doesn't even work well with synchronous functions](http://stackoverflow.com/a/21631463/1048572). But yes, [mapping asynchronous tasks over a collection in parallel is easy with promises](http://stackoverflow.com/q/18017980/1048572). – Bergi Jul 19 '14 at 16:45
  • @jfriend00: That's in the last paragraph of my answer already :-) – Bergi Jul 19 '14 at 16:46
  • Perhaps I didn't phrase my question as well as I should have; the issue is that I didn't want some synchronous operations on an array to be blocking. I know you can't really do true parallelism in JS without something like a Web Worker. – Tombert Jul 19 '14 at 17:33
  • @Tombert: Then that sounds like a duplicate of [the question that jfriend has already pointed to](http://stackoverflow.com/questions/10344498/best-way-to-iterate-over-an-array-without-blocking-the-ui/10344560#10344560) – Bergi Jul 19 '14 at 17:39
2

First off, promises won't help you make code run in parallel. They are a tool for running other code when your task is done or coordinating this task with other tasks. But making your current code run in parallel with other code has nothing to do with promises.

Second off, there's little advantage (and a lot of complication) to taking a synchronous task and trying to make it work more like an asynchronous tasks unless it is so long running that it interferes with the responsiveness of other operations. Computing a set of random numbers is unlikely to be that long a running task.

If you truly want parallel execution in a browser, you would have go use WebWorkers which is the only way to create an truly independent execution thread in browser-based javascript. Other than WebWorkers, javascript in a browser is single threaded so there is no parallel execution. It is possible to execute small chunks of code on successive setTimeout() calls which will interweave your code execution with other things going on in the browser and can allow other browser tasks to remain responsive while running another long running task.

You can see an example of processing a large array in chunks using setTimeout() here Best way to iterate over an array without blocking the UI to allow other things to run in between chunks of processing. Promises could be added to something like this as a method of managing the completion of the task or managing its coordination with other tasks, but promises don't actually help you make it work in chunks.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • The `setTimeout` idea worked perfectly. I'm not actually using it for Math.random, but I just thought of it as the first synchronous code that popped into my brain. – Tombert Jul 19 '14 at 17:09