You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've seen this requested a few times in StackOverflow now:
People have code that is asynchronous and would like to use values from it in the REPL:
// how do I access in the REPL? returns promise
Transaction.where('reference', '1').fetch().then((res) => { return res });
A common workaround is to store a global reference in the REPL, which is a little hacky and relies on timing, but can work for simple cases:
> Transaction.where('reference', '1').fetch().then((res) => out = res)
[Object Promise]
> out
/* response available here*/
This works, but has timing issues and generally isn't great. We could however run the REPL in the context of an async function potentially - which would allow awaiting values in the REPL:
let res = await Transaction.where('reference', '1').fetch();
I think it could be an interesting enhancement but would like more feedback on the idea. @nodejs/collaborators
I looked into implementing this when Node 7.6.0 came out and async functions were originally added. At first glance it seemed like it would be a bit difficult because the REPL currently doesn't run in a function context at all. However, there might be a better solution that I'm not aware of.
await-repl seems to only await a promise if the line starts with "await ", which is probably insufficient (e.g. it doesn't allow foo = await bar().
repl.js seems to auto-await all Promises that are returned from an eval, but that also probably isn't what we want (and it doesn't allow for nested await either).
I'm not arguing that this is a beneficial feature. But IMHO the REPL is an exploratory tool, so those tools at least enable easier exploration 🤷♂️
On the other hand the cli -e option, again IMHO, is a more "important" feature to enable easy await usage for. node -e "await new Promise.resolve(4)"
It would definitely be possible in theory by reimplementing await semantics and parsing, but that seems like a lot of work. Ideally there would be some --allow-top-level-await flag in V8 that we can use.
@ChALkeR what semantics would it change? I figured that since the REPL is not synchronous anyway (being user input and all) the microtick of wrapping it in an async function - unwrapping it and giving the user back the result wouldn't be too bad.
@filips123 when await is enabled we run input through a separate parser which doesn't necessarily match the way node normally parses code, so there could be incompatibilities. In the long run, a combination of top-level-await and a standardized repl parse goal should fix this.
Summary, it works with an experimental flag. use something like the following to load some js and drop you into a repl after the variables are set, kind of like bashrc.
Top level await is now supported in V8 (https://v8.dev/features/top-level-await)
Is it possible to add something like vm.runAsyncInContext to avoid using a different parser for code containing async in repl?
Also, I could really use vm.runAsyncInContext for a jupyter-notebook-like node project.
When the adding the command line --experimental-repl-await is not an option, one could use this hack to always await promises on a custom REPL:
constdefaultEval=myRepl.eval;myRepl.eval=(cmd,context,filename,callback)=>{defaultEval(cmd,context,filename,async(err,result)=>{if(err){// propagate errors from the evalcallback(err);}else{// awaits the promise and either return result or errortry{callback(null,awaitPromise.resolve(result));}catch(err){callback(err);}}});};
It is not a general solution but worked well for my use case.
When the adding the command line --experimental-repl-await is not an option, one could use this hack to always await promises on a custom REPL:
constdefaultEval=myRepl.eval;myRepl.eval=(cmd,context,filename,callback)=>{defaultEval(cmd,context,filename,async(err,result)=>{if(err){// propagate errors from the evalcallback(err);}else{// awaits the promise and either return result or errortry{callback(null,awaitPromise.resolve(result));}catch(err){callback(err);}}});};
It is not a general solution but worked well for my use case.
// index.jsconstrepl=require("repl");constmyRepl=repl.start();constdefaultEval=myRepl.eval;myRepl.eval=(cmd,context,filename,callback)=>{defaultEval(cmd,context,filename,async(err,result)=>{if(err){// propagate errors from the evalcallback(err);}else{// awaits the promise and either return result or errortry{callback(null,awaitPromise.resolve(result));}catch(err){callback(err);}}});};
usage node index.js
type:
functiondelayPromise(delay){//async delay functionreturnnewPromise(resolve=>setTimeout(()=>resolve(),delay))}delayPromise(3000)undefined//wait 3 seconds until can proceed typing
I'm not sure why, but using --experimental-repl-await affects how util.inspect.defaultOptions are interpreted. In normal code you could adjust the output of console.log using the following:
The docs seem to suggest that the replDefaults should mirror defaultOptions, but this doesn't seem to be the case when using the async version of the REPL.
Activity
not-an-aardvark commentedon May 24, 2017
👍
I looked into implementing this when Node 7.6.0 came out and async functions were originally added. At first glance it seemed like it would be a bit difficult because the REPL currently doesn't run in a function context at all. However, there might be a better solution that I'm not aware of.
refack commentedon May 24, 2017
I'm +1.
But there are userland solutions, quick googling found https://github.com/skyrising/await-repl, https://github.com/StreetStrider/repl.js, and I'm sure there are more
not-an-aardvark commentedon May 24, 2017
await-replseems to only await a promise if the line starts with "await ", which is probably insufficient (e.g. it doesn't allowfoo = await bar().repl.jsseems to auto-await all Promises that are returned from an eval, but that also probably isn't what we want (and it doesn't allow for nestedawaiteither).refack commentedon May 24, 2017
I'm not arguing that this is a beneficial feature. But IMHO the REPL is an exploratory tool, so those tools at least enable easier exploration 🤷♂️
On the other hand the cli
-eoption, again IMHO, is a more "important" feature to enable easyawaitusage for.node -e "await new Promise.resolve(4)"vkurchatkin commentedon May 24, 2017
The question is, is it really possible? It seems like it's not
not-an-aardvark commentedon May 24, 2017
It would definitely be possible in theory by reimplementing
awaitsemantics and parsing, but that seems like a lot of work. Ideally there would be some--allow-top-level-awaitflag in V8 that we can use.joyeecheung commentedon May 25, 2017
There was a feature request issue for this and there are some solutions proposed there: #8382 although it seems most of them are somewhat hacky
benjamingr commentedon May 25, 2017
@vkurchatkin
Why can't we just wrap the content with an async function?
ChALkeR commentedon May 25, 2017
@benjamingr, that will change the semantics of repl. We need to detect it somehow, or use a flag, or force this as a semver-major change for everyone.
benjamingr commentedon May 25, 2017
@ChALkeR what semantics would it change? I figured that since the REPL is not synchronous anyway (being user input and all) the microtick of wrapping it in an async function - unwrapping it and giving the user back the result wouldn't be too bad.
Am I missing anything?
targos commentedon May 25, 2017
@benjamingr do you have ideas about how to make this work:
If we wrapped the code in an async function,
bwould be local to this function. How to unwrap it?83 remaining items
filips123 commentedon Jul 1, 2019
Is there any specific reason why is
awaitunder an experimental flag? Why is it not enabled by default?devsnek commentedon Jul 1, 2019
@filips123 when await is enabled we run input through a separate parser which doesn't necessarily match the way node normally parses code, so there could be incompatibilities. In the long run, a combination of top-level-await and a standardized repl parse goal should fix this.
https://github.com/tc39/proposal-top-level-await
https://github.com/bmeck/js-repl-goal
FossPrime commentedon Jul 19, 2019
Summary, it works with an experimental flag. use something like the following to load some js and drop you into a repl after the variables are set, kind of like bashrc.
With enough run commands, it might be possible to replace bash with node lol
https://stackoverflow.com/questions/33850903/use-node-js-as-shell
nahtnam commentedon Sep 5, 2019
Has anyone figured out how to get the experimental flag to work in a REPL that is spawned with
.start()? The following snippet doesn't work.aherlihy commentedon Oct 3, 2019
Having the same issue as @nahtnam with trying to get await mode turned on from
repl.start. Any suggestions?bapti commentedon Dec 1, 2019
I did this and it worked
And in
repl.jsWhen I run it it works fine and I can await on my function readFileToArray
tomasgvivo commentedon Mar 27, 2020
Top level await is now supported in V8 (https://v8.dev/features/top-level-await)
Is it possible to add something like
vm.runAsyncInContextto avoid using a different parser for code containingasyncin repl?Also, I could really use
vm.runAsyncInContextfor a jupyter-notebook-like node project.devsnek commentedon Mar 28, 2020
@tomasgvivo TLA is part of modules. Once we land support for it (#30370), you can use it in a
vm.SourceTextModuleinstance.There is another thing V8 is working on called "repl mode" which might help with await in the repl though: https://docs.google.com/document/d/1bIKMRrLVObsAfmMAQ-tmsWkQZu1cFg87RRrPpiwTL2M/edit
cyrus-and commentedon Apr 26, 2020
When the adding the command line
--experimental-repl-awaitis not an option, one could use this hack to always await promises on a custom REPL:It is not a general solution but worked well for my use case.
YoraiLevi commentedon Jun 3, 2020
usage
node index.jstype:
Adds await support to strapis REPL console
andyvanee commentedon Oct 20, 2020
I'm not sure why, but using
--experimental-repl-awaitaffects howutil.inspect.defaultOptionsare interpreted. In normal code you could adjust the output ofconsole.logusing the following:But when using
--experimental-repl-awaitit needs to be changed to this:The docs seem to suggest that the
replDefaultsshould mirrordefaultOptions, but this doesn't seem to be the case when using the async version of the REPL.[from now] 2021/09/12 20:25:28
[from now] 2021/09/12 20:33:11
repl: support top-level await