First and foremost, let's address the bounty note.
[I hope to award points to someone who provides more insight than just saying "Avoid using promises"... ]
Unfortunately, the bottom line here is simply: "Avoid using promises". ES6 Promises present three potential states (from a user perspective): Pending, Resolved, and Rejected (the names may vary slightly).
You cannot access the inner workings of a promise to determine what has been completed and what hasn't – at least not with native ES6 promises. Some limited progress was made on promise notifications in other frameworks, but this functionality didn’t make it into the ES6 specification; therefore, utilizing it would be unwise, even if you manage to find an implementation for it.
A promise's purpose is to represent an asynchronous task that will occur in the future; standalone, it isn’t suitable for this use case. What you likely need is more akin to an event publisher - and even that operates asynchronously, not synchronously.
There isn’t a reliable way for you to synchronously retrieve a value from an asynchronous call, especially within JavaScript. One significant reason for this is that a well-designed API will always opt for asynchrony when feasible.
Consider the following scenario:
const promiseValue = Promise.resolve(5)
promiseValue.then((value) => console.log(value))
console.log('test')
If this promise were resolved synchronously (since we know the value ahead of time), what outcome would you anticipate? A typical expectation might be:
> 5
> test
However, the actual sequence is as follows:
> test
> 5
This discrepancy arises because while Promise.resolve()
is a synchronous operation that resolves an already-resolved Promise, then()
consistently functions asynchronously; this is a fundamental guarantee of the specification, serving to enhance code understanding - envision the complications that could arise from blending synchronous and asynchronous promises.
This principle holds true for all asynchronous tasks: any potentially asynchronous action in JavaScript definitively operates asynchronously. Consequently, no synchronous introspection can be performed within any JavaScript-provided API.
This doesn’t imply that developing a wrapper around a request object is impossible, such as:
function makeRequest(url) {
const requestObject = new XMLHttpRequest()
const result = {
}
result.done = new Promise((resolve, reject) => {
requestObject.onreadystatechange = function() {
..
}
})
requestObject.open(url)
requestObject.send()
return requestObject
}
Nonetheless, this approach quickly becomes convoluted, necessitating some form of asynchronous callback to operate effectively. Challenges arise particularly when implementing Fetch
. Moreover, bear in mind that Promise cancellation hasn’t been standardized yet. Refer to here for further insights on this aspect.
TL:DR: It’s impossible to introspect synchronously on any asynchronous task in JavaScript, and utilizing a Promise for such endeavors is ill-advised. You’re incapable of synchronously displaying details about an ongoing request, for instance. In alternative programming languages, attempting this would demand blocking or inadvertently triggering a race condition.