GeezerVison is showing github.com — repl: allow `await` in REPL · Issue #13209 · nodejs/node
repl: allow await in REPL #13209DescriptionI'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 Reacted by Teddy Katz, Refael Ackermann, Alexander Frisch, Sindre Sorhus, Bergi, no, Ivo Todorov, ebraminio, Tomas Della Vedova, pannous and 124 more Reacted by Sergey Rubanov and Luis Eduardo Brito Reacted by pannous, Adrien Becchis, Kothique Félixx, Luis Eduardo Brito, Ahmad Said, ExE Boss and Joe Lust Reacted by juno suárez, Radon Rosborough, Gabriele Tomberli, Casu, Adrien Becchis, Motoi Washida, Alexander Ivanov, Kothique Félixx, Luis Eduardo Brito, A Flores and 4 more Reacted by ExE Boss Reacted by Antonio Ferrándiz and Hydrophobefireman Activitynot-an-aardvark commented on 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. Reacted by Benjamin Gruenbaum refack commented on May 24, 2017 not-an-aardvark commented on May 24, 2017 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).
refack commented on 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 -e option, again IMHO, is a more "important" feature to enable easy await usage for.
node -e "await new Promise.resolve(4)" vkurchatkin commented on May 24, 2017 The question is, is it really possible? It seems like it's not Reacted by Sergey Rubanov and Den Rupp not-an-aardvark commented on May 24, 2017 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. joyeecheung commented on 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 commented on May 25, 2017 @vkurchatkin
The question is, is it really possible? It seems like it's not
Why can't we just wrap the content with an async function? ChALkeR commented on 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 commented on 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 commented on May 25, 2017 @benjamingr do you have ideas about how to make this work:
> const a = Promise.resolve(42);
undefined
> const b = await a;
undefined
> b
42
If we wrapped the code in an async function, b would be local to this function. How to unwrap it? Reacted by Benjamin Gruenbaum, Andy Edwards and Mourad Kejji filips123 commented on Jul 1, 2019 Is there any specific reason why is await under an experimental flag? Why is it not enabled by default? Reacted by Chris Talman and Sablier Bot devsnek commented on Jul 1, 2019 FossPrime commented on 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.
#!/bin/bash
node --experimental-repl-await -i -e "$(< scripts/repl.js)"`
With enough run commands, it might be possible to replace bash with node lol
https://stackoverflow.com/questions/33850903/use-node-js-as-shell Reacted by Ray Foss, hadroncfy and Jure Triglav nahtnam commented on 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.
process.env.NODE_OPTIONS = '--experimental-repl-await';
const local = repl.start({ prompt: '> ' });
Reacted by Filip Štamcar, Sam Yau, anna herlihy and Philippe Serhal aherlihy commented on Oct 3, 2019 Having the same issue as @nahtnam with trying to get await mode turned on from repl.start. Any suggestions? bapti commented on Dec 1, 2019 I did this and it worked
"scripts": {
"repl": "node --experimental-repl-await ./repl.js"
}
And in repl.js
const { readFileToArray } = require("./utils");
const repl = require("repl");
repl.start("> ").context.readFileToArray = readFileToArray;
When I run it it works fine and I can await on my function readFileToArray Reacted by Iddan Aaronsohn, Ryan Wersal, Guillaume Massé (马赛卫), Alex Yang, Yang-Hsing Lin and Jerry Baba tomasgvivo commented on 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.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. devsnek commented on Mar 28, 2020 Reacted by ExE Boss and Tomas Gonzalez Vivo cyrus-and commented on Apr 26, 2020 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:
const defaultEval = myRepl.eval;
myRepl.eval = (cmd, context, filename, callback) => {
defaultEval(cmd, context, filename, async (err, result) => {
if (err) {
// propagate errors from the eval
callback(err);
} else {
// awaits the promise and either return result or error
try {
callback(null, await Promise.resolve(result));
} catch (err) {
callback(err);
}
}
});
};
It is not a general solution but worked well for my use case. Reacted by Sean Dunford Reacted by Aaryamann Challani YoraiLevi commented on Jun 3, 2020
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:
const defaultEval = myRepl.eval;
myRepl.eval = (cmd, context, filename, callback) => {
defaultEval(cmd, context, filename, async (err, result) => {
if (err) {
// propagate errors from the eval
callback(err);
} else {
// awaits the promise and either return result or error
try {
callback(null, await Promise.resolve(result));
} catch (err) {
callback(err);
}
}
});
};
It is not a general solution but worked well for my use case.
// index.js
const repl = require("repl");
const myRepl = repl.start();
const defaultEval = myRepl.eval;
myRepl.eval = (cmd, context, filename, callback) => {
defaultEval(cmd, context, filename, async (err, result) => {
if (err) {
// propagate errors from the eval
callback(err);
} else {
// awaits the promise and either return result or error
try {
callback(null, await Promise.resolve(result));
} catch (err) {
callback(err);
}
}
});
};
usage node index.js
type:
function delayPromise(delay){
//async delay function
return new Promise(resolve => setTimeout(() => resolve(), delay))
}
delayPromise(3000)
undefined
//wait 3 seconds until can proceed typingReacted by Sean Dunford Reacted by Jimmie Tyrrell andyvanee commented on Oct 20, 2020 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:
import util from "util"
util.inspect.defaultOptions.getters = true
util.inspect.defaultOptions.depth = 4
util.inspect.defaultOptions.maxStringLength = 80
But when using --experimental-repl-await it needs to be changed to this:
import util from "util"
util.inspect.replDefaults.getters = true
util.inspect.replDefaults.depth = 4
util.inspect.replDefaults.maxStringLength = 80
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.
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|