0

Update: This question was pretty misinformed. Basically before you read on, just understand that although I am already constructing fancy promisified routines to do work, I wasn't quite grasping the basic principles of promises and how to use them in an async/await context.

There are exactly two standard and important ways to achieve a continuation from one promise to the next, which is part of what I was asking for:

  1. promises can be chained to other promises with then()
  2. promises can be awaited in sequence within an async function context, and they will wait (hence "await") for completion before proceeding.

What I am asking for is if the first promise in a chain needs to be controlled or predicated, how can I express this cleanly?


I have some existing code which does stuff in a promise.

I am adding a new step to the process that has to happen before it, but conditionally.

Before:

let promise_manipulate_files = util.promisify(_async.eachOfLimit)(fs.readdirSync(directory), 5, (f, _i, cb) => { ... })

After (this code is wrong):

if (filesNeedToBeRenamed()) {
  let promise_rename_files = Promise.all(fs.readdirSync(directory).map(
    file => util.promisify(fs.rename)(file, amendedFilename(file))
      .catch({ ... })
    ));
}
let promise_manipulate_files = util.promisify(_async.eachOfLimit)(fs.readdirSync(directory), 5, (f, _i, cb) => { ... })

The concern is that the second promise must not be allowed to begin until the first promise is completely finished.

This is the top level of my script.

Is the only practical way to get what I want to wrap the entire code in an async () => {} closure and await on the first promise?

The reason that the example is a little more complex than it could be minimally, is because if i show a minimal example, then it's pretty clear that the operations should just be performed synchronously. Indeed I am trying here to enforce a particular kind of synchronous boundary on these tasks.

I believe the crux of the issue here is that the if condition prevents me from being able to directly chain manipulate_files onto rename_files by using .then()!

Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • At no point are you awaiting anything, so essentially all these calls are firing off, and just completing when they finish in the background. The `Promise.all` is completely irrelevant, unless you are actually awaiting it, or calling `.then()` to run something after they call complete. – Blue Oct 09 '18 at 20:10
  • i know that After is behaviorally wrong (edited). that's the question. I know it's wrong, and I know one way to solve it, but it seems really ugly, so I'm asking if there are more elegant ways to solve it. – Steven Lu Oct 09 '18 at 20:11
  • Do you await anywhere at the end? With `promise_manipulate_files`? – Blue Oct 09 '18 at 20:15
  • @FrankerZ Yes. I do. And that works fine. I do that from another part of the code inside an async function. these promises however are not being created in an async function scope. – Steven Lu Oct 09 '18 at 20:15
  • Personally, I would just add the condition in the `(f, _i, cb) => { ... }` (The ...). If the file needs to be renamed, then write out the file, and rename it afterwards. You can always make that function async, and await a rename, or await a write. – Blue Oct 09 '18 at 20:17
  • I really appreciate that @FrankerZ but don't think that'll be necessary. I do understand it, i think that i'm just disillusioned with the level of control that promises provide. I suspect that the simple answer is that the concern I'm pointing out is precisely why async/await got created in the first place. – Steven Lu Oct 09 '18 at 20:21
  • Using async/await, is much easier than chaining a whole bunch of `.then` with conditional statements. If you want the rename process to happen before the second process, you NEED to `await` the `Promise.all` before the second one happens. – Blue Oct 09 '18 at 20:24
  • @FrankerZ that matches up with my understanding. Thanks. – Steven Lu Oct 09 '18 at 20:26

2 Answers2

1

Seems like if filesNeedToBeRenamed() then do it this way otherwise just run the next part unconditionally. so you can reference the promise_manipulate_files as a separate function in both spots or write it twice. But maybe i don't understand the question.

if (filesNeedToBeRenamed()) {
    let promise_rename_files = Promise.all(fs.readdirSync(directory).map(
        file => util.promisify(fs.rename)(file, amendedFilename(file))
          .catch({ ... })
        ));

    // attach .then() callback here (however you can) for promise_manipulate_files
} else {
    // Otherwise, do this unconditionally here
    let promise_manipulate_files = util.promisify(_async.eachOfLimit) 
    (fs.readdirSync(directory), 5, (f, _i, cb) => { ... })
}
Emery King
  • 3,550
  • 23
  • 34
  • 1
    Yeah this is what I was thinking. I'd have to assemble the promise chains independently if really am going to have such an if getting in its way. I think this is just the nature of the beast. pretty ugly. Alternatively I can make the file renaming process an idempotent one that can be run always, thus eliminating the predication. – Steven Lu Oct 09 '18 at 20:25
  • Assigning promise chains is exactly what async/await is trying to help/prevent. This can easily be done with a bunch of await statements, in one code block. Not a single `.then()` should be required. – Blue Oct 09 '18 at 20:26
1

You could wrap the part into another function and attach it to the .then chain:

 if (filesNeedToBeRenamed()) {
   let promise_rename_files = Promise.all(fs.readdirSync(directory).map(
     file => util.promisify(fs.rename)(file, amendedFilename(file))
      .then(getFile)
      .catch({ ... })
   ));
 } else {
    getFile();
 }

 function getFile() {
   let promise_manipulate_files = util.promisify(_async.eachOfLimit)(fs.readdirSync(directory), 5, (f, _i, cb) => { ... })
 }

Or you just use async / await.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • 1
    You deciphered my poorly simplified question. I've attempted to edit and clarify the question, and i've given you the accept. Thanks. – Steven Lu Sep 17 '19 at 02:03