更正 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 的声明被提升,因此,您可以在 before 行 var 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 中的异步函数导出的主要内容,如果未能解决你的问题,请参考以下文章