HelloWorld
HelloWorld

Reputation: 1863

How to execute another promise in finally?

I have a promise chain and I need to write to a file using fs.writeFile after the chain is executed. As far as I can see, finally accepts a Promise as a return type:

finally(onfinally?: (() => void) | undefined | null): Promise<T>

But looking at my code, eslint doesn't seem to like it:

My Code:

    return this.downloadProject(data)
      .finally(() => {
        return fse.writeFile('', 'foo');
      })

VSCode:

enter image description here

Is this caused by a misconfiguration of my Eslint or is this a code smell?

Upvotes: 1

Views: 1888

Answers (3)

Another alternative solution

function wait1sec() {
  return new Promise((resolve, reject) => {
    setTimeout(()=>resolve(1), 1000)
  });
}

wait1sec()
  .then((res) => {
    console.log(res);
    return wait1sec()
  })
  .catch((err) => {
    console.error(err);
  })
  .finally(() => {
    console.log(2)
    return wait1sec()
  })
  .finally(() => {
    console.log(3);
    return wait1sec()
  })
  .finally(() => {
    console.log(4);
  })
  .finally(() => {
    console.log(5);
  })

Upvotes: 0

trincot
trincot

Reputation: 350290

The ECMAScript specification has for finally, in step 6:

i. Let result be ? Call(onFinally, undefined).
ii. Let promise be ? PromiseResolve(C, result).
...etc

So there is a use for the value returned. If this return value happens to be a promise, then the promise returned by finally will be locked into the promise returned by its callback. However, the resolution value will still be that of the original promise.

This can be seen in the following test script:

Promise.resolve(3)
       .finally(() => new Promise(resolve => 
            setTimeout(() => resolve(5), 2000))
        )
       .then((value) => console.log("resolved to", value));

// Message appears after 2 seconds, and value is 3

And similarly, when the original promise is rejected, the promise returned in the finally callback is awaited, but the rejection remains:

Promise.reject(3)
       .finally(() => new Promise(resolve => 
            setTimeout(() => resolve(5), 2000))
        )
       .catch((value) => console.log("rejected with", value));

// Message appears after 2 seconds, and value is 3

There is a clearly a consequence to returning a promise in the finally callback, so we could argue that the linter should not complain about it.

Ignoring a rejection

If you want to work around this linter warning, or if you really want to have the effect of a then, so that it returns a new promise with its own outcome, than weave a .catch just before a .then:

return this.downloadProject(data)
      .catch(() => {})  // This promise will fulfill after a rejection
      .then(() => {
        return fse.writeFile('', 'foo');
      })

Upvotes: 4

Eldar B.
Eldar B.

Reputation: 1327

The .finally returns a promise, in order to allow promise-chaining. However, the function inside should not return anything, hence the () => void | undefined.

Upvotes: 2

Related Questions