I think you need to understand the reason why rejections are needed, the problem it tries to solve. Consider a simple example such as this:
try {
iDoNotExist
} catch(e) {
//e ReferenceError
}
Pretty simple, the code is being evaluated and "tried" for errors. There's such an error and well, it gets caught.
Now, what if we changed it a little bit into this:
try {
setTimeout(function(){ iDoNotExist }, 1000);
} catch(e) {
//e ReferenceError
}
If you run this code, you'll notice that your javascript environment will emit an Error. It's not being caught here. Why? Because the code that throws the error is not being run when it's being "tried", only the setTimeout
function which simply schedules the function and well, that function is doing it's job, it's scheduling it correctly. This in turn is the same reason why so many people get it wrong when they try accessing a value that's product of an async function. E.g.
let result;
setTimeout(() => result = true, 1000);
console.log(result) // Why is this undefined? - Famous last question
Enter promises to the rescue, which not only allow you to recover a value which you would typically return
, it also lets you recover any potential error that happens on said async operations. Providing you with semantics that are similar with synchronous code (even more when paired with async
functions).
So, I would say rejections are complementary to exceptions. To preserve your program flow when there's an asynchronous boundary (just like fulfilled promises do to preserve function composition).
As for what you would call unfulfilled well... there's a couple of things. unfulfilled means "not fulfilled". A rejected promise IS, technically, an unfulfilled promise. However, an unresolved promise (a promise in a pending state) is ALSO an unfulfilled promise. Technically.
Most people will think of the latter but really it could be either. Mostly because it comes from a time where "fulfill" and "resolve" where used interchangeably (which is wrong). But also because that's typically the expected result of a promise resolution.
Under no circumstance is an unresolved promise a rejected promise. An unresolved promise is in a transitory state in which it could transit into either a fulfilled promise or a rejected one.