1

Maybe this is a stupid ask but I recently found myself using this abstraction often:

async function giveMeAName(cbAsync, initValue) {
  return await Promise.all(
    initValue.map(cbAsync),
  );
}

Question: Is this a common task to anyone else? If so, does it have a name? If not, maybe it's only partly realize, so does it remind you of anything? Otherwise, I can just delete the question.

Currently I'm using this function for this set of instructions. Code below will get all directories of a path and collect all directories that have a package.json within:

const directories = (await getDirNamesByPath(rootPath));
const paths = await giveMeAName(addExistAdaptor, directories.map(joinPathWithName(rootPath)));
return await giveMeAName(collectJson, paths.filter(hasPath));
Armeen Moon
  • 18,061
  • 35
  • 120
  • 233
  • 1
    Btw., strictly speaking, this isn't functional, because FP is based on laws, mostly math laws. From this perspective, `Promise` is a lawless datatype who's acting weird. You should look into monadic types like `Task`, which handle asynchronous computations. –  May 21 '19 at 18:17

3 Answers3

2

You asked a related question a couple days ago that I tried helping you with, but you never replied :(

I've answered similar questions (here and here) that have generalised this pattern -

const Parallel = p =>
  ( { map: async f =>
        Promise .all ((await p) .map (x => f (x)))
    , filter: async f =>
        Promise .all ((await p) .filter (x => f (x)))
    , flatMap: async f =>
        Promise .all ((await p) .map (x => f (x))) .then (ys => [] .concat (...ys))
    , // ...
    }
  )

You can see it being used in this way with files, which recursively lists all paths to all files in a directory and its subdirectories -

const { readdir, stat } =
  require ("fs") .promises

const { join } =
  require ("path")

const files = async (path = ".") =>
  (await stat (path)) .isDirectory ()
    ? Parallel (readdir (path))
        .flatMap (f => files (join (path, f)))
    : [ path ]

And a specialisation, search, which returns all paths matching a query -

const { basename } =
  require ("path")

const search = async (query, path = ".") =>
  Parallel (files (path))
    .filter (f => basename (f) === query)

And readPackages which recursively reads all package.json files at a specified path -

const { readFile } =
  require ("fs") .promises

const readPackages = async (path = ".") =>
  Parallel (search ("package.json", path))
    .map (readFile)
    .then
      ( buffers =>
          buffers .map (b => JSON .parse (String (b)))
      )

Finally, a slightly more complex example, dirs, which works like files but recursively lists directories only. The level of recursion can be controlled by the depth parameter -

const dirs = async (path = ".", depth = Infinity) =>
  (await stat (path)) .isDirectory ()
    ? depth === -1
        ? []
        : Parallel (readdir (path))
            .flatMap (f => dirs (join (path, f), depth - 1))
            .then (results => [ path, ...results ])
    : []

To see what these programs look like without the Parallel module, see the linked Q&A's above.

Mulan
  • 129,518
  • 31
  • 228
  • 259
0

I use different names for it, depending on my needs in the application. Sometimes I use functions like that for specific use cases and name it accordingly. But the most generic name that I use quite often, is simply resolveAll().

But I don't think there is any (semi-)official naming for it. So name it the way it makes the most sense to you.

Robbeoli
  • 408
  • 5
  • 17
0

Perhaps mapAll or awaitAll?

Bluebird has a similar function simply called map() which does something quite similar (it returns the mapped promise rather than resolving it).

Kenan Banks
  • 207,056
  • 34
  • 155
  • 173