-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add utility to synchronously inspect promise state #40054
Comments
I am strongly opposed to exposing this functionality. |
@devsnek Why? Reflection capabilities are quite common in other languages. |
@sindresorhus we have reflection capabilities in node as well, check out the inspector module. Anything more first-class would be improper to expose as it would encourage people to do weird zalgo timing "optimizations" or have strange zalgo test assertions. |
Anything can be misused. Good docs can help prevent that. Node.js has lots of synchronous APIs, for example, even though it can be misused in a server setting. |
@sindresorhus ... What's the basic use case you have in mind? Specifically, why do you want to know the pending status vs. just getting the results? |
@jasnell One use case would be test assertions. |
why would you need this for a test assertion? |
Can't this mostly be solved with a wrapper roughly like this: const getPromiseWithStatus = (input) => {
const result = Promise.resolve(input);
result.status = 'pending';
result.then(
() => result.status = 'fulfilled',
() => result.status = 'rejected'
);
return result;
}; Sure, if given an already fulfilled/rejected promise it will not be able to give an answer in sync, but if wrapped early on it can? |
For the assertions thing I've used basically the same as the approach above and have had no issues. For optimization cases I doubt there's many uses that need to get the resolved value of a promise from an arbitrary source. Most cases that are happy to commit to supporting having a value available earlier will provide a synchronous version or an event. I can see uses for getting the resolved value of promises vended from the same code that needs to access it, but this should be doable with some simple helpers. |
I feel this is better solved on language level, e.g. raise an ECMAScript proposal. Having a non-standard node API would be detrimental. |
Just discovered this sweet solution: function promiseStateSync(promise) {
let state = 'pending';
promise
.then(() => {
state = 'fulfilled';
})
.catch(() => {
state = 'rejected';
});
process._tickCallback();
return state;
} The only thing I'm uncertain of is whether |
And it's quite a popular need: https://stackoverflow.com/questions/30564053/how-can-i-synchronously-determine-a-javascript-promises-state |
@voxpelli That's pretty much how my package works: https://github.com/sindresorhus/p-state/blob/main/browser.js |
@silverwind You could use that argument about a lot of the existing Node.js APIs. Having it in the language would be ideal, but it's a much higher barrier. |
The other challenge with having it at the language level is that this has been considered there already as far as I'm aware. I'm not opposed to us exposing an API, I'm just concerned about it being misused. @sindresorhus' use cases are legitimate but it's entirely likely that folks will come up with more problematic uses. Another challenge here, however, is that whatever we might add here will be specific to Node.js and won't work in other platforms (browsers, deno, workers, etc). I think we can expose the utility, with heavy warnings in the docs, then see if tc39 is willing to reconsider. |
I can just say now, the likelihood of tc39 finding consensus on such a feature is basically zero. the entire point of promises is that you can't inspect their state synchronously. for your optimization use case, I would just suggest not using promises. if the code is a public api and you can't not use promises that's a good sign that your optimization would be a brittle zalgo issue. for testing, this test makes no sense to me. why does this test care about the tick by tick state of the promise? I'd just set a |
At the risk of spilling some “forbidden” knowledge: $ cat > test.js <<EOF
const vm = require('vm');
const p = Promise.resolve(42);
vm.runInNewContext(
"p.then(() => p.status = 'fulfilled', () => p.status = 'rejected');",
{ p },
{ microtaskMode: 'afterEvaluate' })
console.log(p.status);
EOF
$ node -v
v14.17.6
$ node test.js
fulfilled |
🤯 Version without mutations: import vm from 'node:vm';
export function promiseStateSync(promise) {
const data = {
state: 'pending',
promise,
};
vm.runInNewContext(`
data.promise
.then(() => {
data.state = 'fulfilled';
})
.catch(() => {
data.state = 'rejected';
})
`, {data}, {microtaskMode: 'afterEvaluate'});
return data.state;
} |
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document. |
unstale |
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document. |
unstale |
Use case would be in Promise.race. for instance, |
@jlee474 That's something you can use Core principle: const nonPendingValue = {};
if (nonPendingValue === await Promise.race([possiblyPendingPromise, nonPendingValue])) {
// possiblyPendingPromise is still pending
} I think you would need to define when there would be a need to do it synchronously. |
Various solutions have been mentioned and there's no consensus about adding this to node natively so I'm going to go ahead and close this out. |
Found this while looking for an idiomatic solution for inspecting promises. Our use case is a NodeJS app with a few hundred tests, each of which may or may not create a promise which "outlives" the test logic, introducing race conditions and flaky test runs. We want to identify these tests without needing to read each one and trace every function call. We can use a mocha plugin:
|
Is your feature request related to a problem? Please describe.
In most cases, you should just await the promise and get its value, even if the promise has already resolved. However, it could sometimes be useful to get the state of the promise. For example, as an optimization to only do a heavy operation if the promise in a certain state or for assertions when writing tests.
Describe the solution you'd like
There used to be
process.binding('util').getPromiseDetails(promise)
, but it was removed in Node.js 16. I suggest exposing autil.promiseState(promise)
method which would return'pending' | 'fulfilled' | 'rejected'
depending on the promise state.Describe alternatives you've considered
I have made a package for this, but it depends on parsing
util.inspect()
output which is a bit fragile.The text was updated successfully, but these errors were encountered: