【问题标题】:How can I wait for a callback before returning from eval()?如何在从 eval() 返回之前等待回调?
【发布时间】:2021-10-10 00:16:47
【问题描述】:

我有一个 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 在退出之前等待回调?我看过承诺,它们看起来很有前途(双关语),但我需要有人引导我朝着正确的方向前进。

【问题讨论】:

  • 为什么没有js 代码在.js/ts 文件中,只需在需要的地方导入?
  • @Muhammad Usman js 代码不是直接来自文件,在这个过程中还有一些其他的东西。我只是说让它更简单,因为它并不重要

标签: javascript node.js asynchronous eval


【解决方案1】:

抛开 eval 的所有缺点,这里直接回答你的问题。


创建一个保持主线程事件循环忙碌的承诺。

从正在 eval 的脚本中解决 promise。该脚本将可以访问 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));

【讨论】:

    【解决方案2】:

    让您的 eval 代码返回一个承诺很好。

    示例:

    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 代码中调用 resolvereject

    例如:

    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 的异步版本

    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);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-01-06
      • 1970-01-01
      • 2020-04-17
      • 2014-11-26
      • 2019-06-11
      • 1970-01-01
      • 2016-09-03
      相关资源
      最近更新 更多