【问题标题】:Correct async function export in node.js更正 node.js 中的异步函数导出
【发布时间】:2018-03-24 17:42:56
【问题描述】:

我的自定义模块包含以下代码:

module.exports.PrintNearestStore = async function PrintNearestStore(session, lat, lon) {
...
}

如果在我的模块外部调用该函数,它工作正常,但是如果我在内部调用,我在运行时出错:

(node:24372) UnhandledPromiseRejectionWarning: 未处理的承诺 拒绝(拒绝 id:1):ReferenceError:PrintNearestStore 不是 定义

当我将语法更改为:

module.exports.PrintNearestStore = PrintNearestStore;

var PrintNearestStore = async function(session, lat, lon) {

}

它开始在模块内正常工作,但在模块外失败 - 我收到错误:

(node:32422) UnhandledPromiseRejectionWarning: 未处理的承诺 拒绝(拒绝 id:1):TypeError:mymodule.PrintNearestStore 是 不是函数

所以我将代码更改为:

module.exports.PrintNearestStore = async function(session, lat, lon) {
    await PrintNearestStore(session, lat, lon);
}

var PrintNearestStore = async function(session, lat, lon) {
...
}

现在它适用于所有情况:内部和外部。但是想了解语义,如果有更漂亮和更短的方法来编写它?如何正确定义和使用async函数:内部和外部(导出)模块?

【问题讨论】:

    标签: javascript node.js async-await


    【解决方案1】:

    这与异步函数没有任何关系。如果你想在内部调用一个函数导出它,先定义它然后导出它。

    async function doStuff() {
      // ...
    }
    // doStuff is defined inside the module so we can call it wherever we want
    
    // Export it to make it available outside
    module.exports.doStuff = doStuff;
    

    解释您的尝试遇到的问题:

    module.exports.PrintNearestStore = async function PrintNearestStore(session, lat, lon) {
    ...
    }
    

    这并没有在模块中定义函数。函数定义是一个函数表达式。函数表达式的名称仅在函数本身内部创建一个变量。更简单的例子:

    var foo = function bar() {
      console.log(typeof bar); // 'function' - works
    };
    foo();
    console.log(typeof foo); // 'function' - works
    console.log(typeof bar); // 'undefined' - there is no such variable `bar`

    另见Named function expressions demystified。如果你想到处引用module.exports.PrintNearestStore,你当然可以引用这个函数。


    module.exports.PrintNearestStore = PrintNearestStore;
    
    var PrintNearestStore = async function(session, lat, lon) {
    
    }
    

    几乎没问题。问题是当您将PrintNearestStore 分配给module.exports.PrintNearestStore 时,它的值是undefined。执行顺序为:

    var PrintNearestStore; // `undefined` by default
    // still `undefined`, hence `module.exports.PrintNearestStore` is `undefined`
    module.exports.PrintNearestStore = PrintNearestStore;
    
    PrintNearestStore = async function(session, lat, lon) {}
    // now has a function as value, but it's too late
    

    更简单的例子:

    var foo = bar;
    console.log(foo, bar); // logs `undefined`, `undefined` because `bar` is `undefined`
    var bar = 21;
    console.log(foo, bar); // logs `undefined`, `21`

    如果您更改了顺序,它将按预期工作。


    module.exports.PrintNearestStore = async function(session, lat, lon) {
        await PrintNearestStore(session, lat, lon);
    }
    
    var PrintNearestStore = async function(session, lat, lon) {
    ...
    }
    

    这是可行的,因为分配给module.exports.PrintNearestStore的函数被执行PrintNearestStore 已将该函数作为其值。

    更简单的例子:

    var foo = function() {
      console.log(bar);
    };
    foo(); // logs `undefined`
    var bar = 21;
    foo(); // logs `21`

    【讨论】:

    • 谢谢,我明白了。只是重新排序了函数定义(删除了var)和module.exports 现在 - 首先是函数定义。我看到内部调用函数定义的顺序并不重要:我在定义之前有函数调用,但是对于module.exports 它很重要。
    • @AlekseyKontsevich: FWIW,源代码中的 A 行 before B 行并不意味着 A 行 执行 before B 行。最后,执行顺序是唯一重要的事情。当然,必须在调用函数之前评估函数定义。但是,由于提升,在 JS 中执行顺序可能并不明显。
    【解决方案2】:

    第一种情况出错:PrintNearestStore - 函数表达式,因此该名称在外部不可用。

    第二种情况的错误:使用变量,而不是函数声明。在这种情况下,变量 PrintNearestStore 的声明被提升,因此,您可以在 beforevar PrintNearestStore = ... 之前使用此名称,但在这种情况下,值将是 undefined

    因此,最简单的解决方案更改第二个变体如下:

    module.exports.PrintNearestStore = PrintNearestStore;
    
    async function PrintNearestStore(session, lat, lon) {
    
    }
    

    【讨论】:

    • 不行:需要先放函数定义,然后module.exports
    • 正如我上面所说,我在节点 8.6 中得到了 UnhandledPromiseRejectionWarning 的此类代码。我把函数定义放在第一位,然后module.exports 修复。
    • @AlekseyKontsevich,为了检测你的错误,我们应该有minimal reproducible example,就像我上面提供的那样
    • 别担心,一切都已经解决了:见上面的答案。你可以删除你的。
    • @AlekseyKontsevich 由于吊装,你把函数放在哪里都没关系。
    【解决方案3】:

    一些例子:

    module.exports.func1 = async function func1(id) {  // name is preferred by linter
      //
    };
    
    module.exports.func1 = async function (id) { // ok
      //
    };
    
    module.exports.func1 = async (id) => { // simpler
      //
    };
    

    【讨论】:

      【解决方案4】:
      export let handlePostStore = async (data) => {
          console.log('post');
          return data;
      };
      
      // to import 
      import { handlePostStore } from 'your_path_here';
      
      // to call it 
      handlePostStore(data)
      

      【讨论】:

      • 代码转储不能提供好的答案。您应该解释如何以及为什么这可以解决他们的问题。我推荐阅读,How do I write a good answer?
      【解决方案5】:

      另一种方法是像这样导出。 // foo.js

      export async function foo(){ 
       console.log('I am greatest of all.'); // for the person who reads it, just say it.
      }
      

      然后在其他脚本中使用它,例如

      import { foo } from './foo'
      
      foo();
      

      【讨论】:

        猜你喜欢
        • 2019-10-28
        • 2019-07-04
        • 2019-01-20
        • 2016-08-17
        • 1970-01-01
        • 1970-01-01
        • 2016-01-02
        • 1970-01-01
        • 2021-05-17
        相关资源
        最近更新 更多