【问题标题】:How to access array from the outer functions?如何从外部函数访问数组?
【发布时间】:2017-04-11 11:53:42
【问题描述】:

我是异步编程的新手

function loadPlugin(plugins, callback) {
    let tests = [[], [], []];
    plugins.forEach((plugin) => {
        f.isPlugin(plugin, (exists) => {
            if (exists) {
                if (!f.pluginIsLoaded(plugin)) {
                    tests[0].push(plugin);
                    f.loadPlugin(plugin);
                } else {
                    tests[1].push(plugin);
                }
            } else {
                tests[2].push(plugin);
            }
        });     
        console.log(tests);       
    });
    return tests;
}

module.exports.isPlugin = (plugin , callback) => {
    fs.access(`./plugins/${plugin}`, fs.constants.F_OK, (err) => {
        callback(!err);
    });
};

f.isPlugin(plugin, (exists) => { }); 内部,我将plugin 推入tests 数组,然后我从外部函数console.log(tests) 显示tests 数组是一个包含3 个空数组的数组。

有没有办法可以保留推入 f.isPlugin(plugin, (exists) => { }); 的内容,以便我可以从外部函数访问它?

【问题讨论】:

  • 使用回调(来自外部函数)来检查该数组,因为回调应该是异步函数中的最后一个操作。异步函数不只是返回,它们回调。
  • 不,你不能。异步结果必须在异步回调中使用,或者您可以从内部范围内调用其他函数并将数据传递给它。您不能在外部范围内同步使用它。您可以在外部范围中使用回调,该回调将从内部范围调用。而且,您还必须等待所有异步操作完成。
  • 你需要确保对数组的操作确实运行完成,并不是你推入数组的东西丢失了,只是还没有发生。
  • 我打电话给f.isPlugin,它在plugins.forEach 内。我希望它让它循环并在返回之前填充tests,我不知道如何处理它。
  • 在许多回调函数中循环应该适合 async.waterfall 也许? "依次运行一系列函数,每个函数将其结果传递给数组中的下一个"

标签: javascript node.js asynchronous ecmascript-6


【解决方案1】:

您可以从回调模式切换到 Promise 并使用 Promise.all 等待所有插件检查完成:

module.exports.isPlugin = plugin => new Promise( resolve =>
    fs.access(`./plugins/${plugin}`, fs.constants.F_OK, err => resolve(!err))
);

function loadPlugin(plugins) {
    let tests = [[], [], []];
    let promises = plugins.map( plugin => 
        f.isPlugin(plugin).then( exists => {
            let status = !exists ? 2 : +f.pluginIsLoaded(plugin);
            if (!status) f.loadPlugin(plugin);
            tests[status].push(plugin);
        })
    );
    // Turn the array of promises into one promise, 
    // which provides the tests array when it resolves:
    return Promise.all(promises).then( _ => tests );
}

所以你可以这样称呼它:

loadPlugin(plugins).then( tests => console.log(tests) );

【讨论】:

    【解决方案2】:

    您可以使用Promisesasync functions

    首先,将isPlugin函数更改为返回Promise

    module.exports.isPlugin = plugin => new Promise(resolve =>
      fs.access(`./plugins/${plugin}`, fs.constants.F_OK, err => resolve(!err))
    );
    

    然后将loadPlugin函数改为异步函数:

    async function loadPlugin(plugins) {
      let tests = [[], [], []];
      for (const plugin of plugins) {
        const exists = await f.isPlugin(plugin);
        if (exists) {
          if (!f.pluginIsLoaded(plugin)) {
            tests[0].push(plugin);
            f.loadPlugin(plugin);
          } else {
            tests[1].push(plugin);
          }
        } else {
          tests[2].push(plugin);
        }
      }
      return tests;
    }
    

    请注意,Node.js 尚不支持异步函数,因此您必须使用 Babel 转译您的代码。

    【讨论】:

      【解决方案3】:

      您不能从带有回调的函数中返回某些内容,您必须调用带有结果的回调函数。这不是访问数组的问题,数组在任何东西有机会被推送之前就被打印出来了。如果你喜欢返回(你应该这样做很有意义),我会推荐使用 Promise。阅读承诺here。我刚刚使用回调做了一个答案,但我意识到这不会每次都奏效。老实说,我不知道如何使用回调来做到这一点。这是一个带有 Promises 的解决方案。

      function loadPlugin(plugins) {
          let tests = [[], [], []];
          // This maps your array to a promise for each one that resolves when the task is complete
          let promises = plugins.map((plugin) => {
            return new Promise((resolve, reject) => {
              f.isPlugin(plugin, (exists) => {
                if (exists) {
                  if (!f.pluginIsLoaded(plugin)) {
                    tests[0].push(plugin);
                    f.loadPlugin(plugin);
                  } else {
                    tests[1].push(plugin);
                  }
                } else {
                  tests[2].push(plugin);
                }
                // Tells the promise the task is complete
                resolve();
              }); 
            });                    
          });
          // Wait for all of the tasks to complete then return tests
          return Promise.all(promises).then(() => tests);
      }
      

      @Gothdo 的解决方案更好,但我不确定您是否使用转译器来使用异步等待语法。我建议这样做并采用他/她的解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-02
        • 1970-01-01
        • 1970-01-01
        • 2017-05-25
        • 2013-02-23
        • 2013-01-18
        相关资源
        最近更新 更多