我有一个node.js脚本,从文件中读取一些JS代码,并将其传递给eval()
。将javascript传递给eval的代码如下:
// read javascript code from file
var outputbuffer = '';
function output(data) {
outputbuffer += data + 'n';
}
eval(javascriptCodeFromFile);
// do stuff with outputbuffer
文件中的javascript代码如下:
var fs = require('fs');
fs.readFile('myfile.txt', function(err, data) {
if (err) {
output('Error reading file');
}
else {
output(data.toString());
}
});
问题是eval在文件读取完成之前退出,因为文件读取是异步的。eval只是开始文件读取,然后退出,而不是等待文件读取完成。如何使eval在退出之前等待回调?我看过承诺,他们似乎很有希望(双关语),但我需要有人引导我在正确的方向。
抛开eval的所有缺点,这里有一个直接的答案
创建一个承诺,以保持主线程的事件循环繁忙。
从正在eval的脚本中解析承诺。该脚本可以访问Promise的resolve and
reject函数,因为求值脚本在Promise的作用域中。
let p = new Promise((resolve, reject) => eval(javascriptCodeFromFile));
p.then(()=> console.log(outputbuffer))
.catch((e) => console.log('Rejected ::' + outputBuffer));
下面是一个可运行的示例,演示了在eval 内部等待异步执行的主线程。
let jsCode = `
setTimeout(() => (resolve('Hello from eval after two seconds')), 2000);
`;
console.log('waiting...');
let p = new Promise((resolve, reject) => {
eval(jsCode);
})
p.then((data)=> console.log(data));
让你的eval代码返回一个promise是可以的。
的例子:
const code = `
new Promise((resolve, reject) => {
var fs = require('fs');
fs.readFile('myfile.txt', function (err, data) {
if (err) {
reject('Error reading file');
}
else {
resolve(data.toString());
}
});
});
`;
console.log('starting...');
eval(code)
.then(str => console.log(str))
.catch(err => console.error(err));
也可以将Promise置于eval
之外,并从eval的代码中调用resolve
或reject
:
例如:
const code = `
var fs = require('fs');
fs.readFile('myfile.txt', function (err, data) {
if (err) {
reject(err);
}
else {
resolve(data.toString());
}
});
`;
console.log('starting...');
new Promise((resolve, reject) => eval(code))
.then(str => console.log(str))
.catch(err => console.error(err));
或者await
和调用readFile
的async版本也是一样的
const code = `
require('fs').promises.readFile('myfile.txt')
`;
console.log('starting...');
main().then(() => console.log('...done'));
async function main() {
try {
let result = await eval(code);
console.log(result);
} catch(err) {
console.error(err);
}
}