更正 node.js 中的异步函数导出

Posted

技术标签:

【中文标题】更正 node.js 中的异步函数导出【英文标题】:Correct async function export in 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函数:内部和外部(导出)模块?

【问题讨论】:

【参考方案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();

【讨论】:

以上是关于更正 node.js 中的异步函数导出的主要内容,如果未能解决你的问题,请参考以下文章

从 Node.js 中的模块导出函数的语法是啥?

返回异步数据,然后在 Node.js 中同步导出

Node.js 中的异步函数

node.js 中的异步函数完成后如何运行函数?

提供 Promise 作为模块的导出是不是是 Node.js 中异步初始化的有效模式?

带你从零学Node.js