Метод finally может вызваться на промисе, который завершается успешно или неуспешно, внутри колбэка может произойти что-то синхронное или асинхронное.
И то и то может быть успешным или неуспешным (в синхронном случае — возврат значения или бросание ошибки, в асинхронном — возврат успешного или неуспешного промиса).
Метод finally вызывается на промисе, который успешно завершается значением value:
в колбэке не возвращается промис:
в колбэке возвращается значение → промис завершается успешно значением value
в колбэке бросается значение error → промис завершается неуспешно с причиной error
в колбэке возвращается промис:
успешный промис резолвится значением promiseOk → промис завершается успешно значением value
неуспешный промис реджектится значением promiseError → промис завершается неуспешно с причиной promiseError
Метод finally вызывается на промисе, который неуспешно завершается с причиной reason:
в колбэке не возвращается промис:
в колбэке возвращается значение → промис завершается неуспешно с с причиной reason
в колбэке бросается значение error → промис завершается неуспешно с с причиной error
в колбэке возвращается промис:
успешный промис резолвится значением promiseOk → промис завершается неуспешно с с причиной reason
неуспешный промис реджектится значением promiseError → промис завершается неуспешно с с причиной promiseError
Описание поведения с MDN:
The finally() method is very similar to calling then(onFinally, onFinally). However, there are a couple of differences
When creating a function inline, you can pass it once, instead of being forced to either declare it twice, or create a variable for it.
The onFinally callback does not receive any argument. This use case is for precisely when you do not care about the rejection reason or the fulfillment value, and so there's no need to provide it.
A finally() call is usually transparent and does not change the eventual state of the original promise. So for example:
Unlike Promise.resolve(2).then(() => 77, () => {}), which returns a promise eventually fulfilled with the value 77, Promise.resolve(2).finally(() => 77) returns a promise eventually fulfilled with the value 2.
Similarly, unlike Promise.reject(3).then(() => {}, () => 88), which returns a promise eventually fulfilled with the value 88, Promise.reject(3).finally(() => 88) returns a promise eventually rejected with the reason 3.
A throw (or returning a rejected promise) in the finally callback still rejects the returned promise. For example, both Promise.reject(3).finally(() => { throw 99; }) and Promise.reject(3).finally(() => Promise.reject(99)) reject the returned promise with the reason 99.