Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/460.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么我使用异步钩子API会导致Node.js异常终止?_Javascript_Node.js_Asynchronous_Async Await_Async Hooks - Fatal编程技术网

Javascript 为什么我使用异步钩子API会导致Node.js异常终止?

Javascript 为什么我使用异步钩子API会导致Node.js异常终止?,javascript,node.js,asynchronous,async-await,async-hooks,Javascript,Node.js,Asynchronous,Async Await,Async Hooks,我已经破坏了Node.js 我正在使用,我的代码使Node.js异常终止 我的问题是:这段代码是什么让Node.js以这种方式终止的?在代码中有什么我可以修改的地方来修复这个问题吗 我的应用程序需要能够在JavaScript笔记本的评估过程中跟踪异步操作,以了解笔记本的评估何时完成 因此,我创建了一个名为的JavaScript类,它包装了异步钩子API,因此我可以对一段代码启用异步跟踪。在代码部分的末尾,我可以禁用跟踪并等待当前异步操作完成 要初始化跟踪,请执行以下操作: this.asyncH

我已经破坏了Node.js

我正在使用,我的代码使Node.js异常终止

我的问题是:这段代码是什么让Node.js以这种方式终止的?在代码中有什么我可以修改的地方来修复这个问题吗

我的应用程序需要能够在JavaScript笔记本的评估过程中跟踪异步操作,以了解笔记本的评估何时完成

因此,我创建了一个名为的JavaScript类,它包装了异步钩子API,因此我可以对一段代码启用异步跟踪。在代码部分的末尾,我可以禁用跟踪并等待当前异步操作完成

要初始化跟踪,请执行以下操作:

this.asyncHook = async_hooks.createHook({ 
    init: (asyncId, type, triggerAsyncId, resource) => {
        this.addAsyncOperation(asyncId, type);
    },
    after: asyncId => {
        this.removeAsyncOperation(asyncId);
    },
    destroy: asyncId => {
        this.removeAsyncOperation(asyncId);
    },
    promiseResolve: asyncId => {
        this.removeAsyncOperation(asyncId);
    },
});

this.asyncHook.enable();
异步操作记录在JS映射中,但它们仅在通过将
trackAsyncOperations
设置为
true
启用跟踪时添加。此变量允许在代码段开始时启用跟踪:

addAsyncOperation(asyncId, type) {
    if (this.trackAsyncOperations) {
        this.asyncOperations.add(asyncId);
        this.openAsyncOperations.set(asyncId, type);
    }
}
各种异步挂钩导致从映射中删除异步操作:

removeAsyncOperation(asyncId) {
    if (this.asyncOperations.has(asyncId)) {
        this.asyncOperations.delete(asyncId);
        this.openAsyncOperations.delete(asyncId);

        if (this.asyncOperationsAwaitResolver && 
            this.asyncOperations.size <= 0) {
            this.asyncOperationsAwaitResolver();
            this.asyncOperationsAwaitResolver = undefined;
        }
    }
}
总而言之,这里有一个使用跟踪程序使Node.js在没有警告的情况下中止的最小示例:

const asyncTracker = new AsyncTracker();
asyncTracker.init();
asyncTracker.enableTracking(); // Enable async operation tracking.

// ---- Async operations created from here on are tracked.

// The simplest async operation that causes this problem.
// If you comment out this code the program completes normally.
await Promise.resolve(); 

// ---  Now we disable tracking of async operations, 
// then wait for all current operations to complete before continuing.

// Disable async tracking and wait.
await asyncTracker.awaitCurrentAsyncOperations(); 
请注意,这一代码并不是一刀切的。当与基于回调或基于承诺的异步操作一起使用时,它似乎工作正常(Node.js正常终止)。只有当我将
wait
关键字添加到混合中时,它才会失败。例如,如果我用调用
setTimeout
替换
wait Promise.resolve()
,它将按预期工作

GitHub上有一个这样的工作示例:

运行该代码使Node.js爆炸。要复制克隆repo,请运行
npm安装
,然后运行
npm启动

此代码已在Windows 10上测试,Node.js版本为8.9.4、10.15.2和12.6.0

此代码现已在MacOS v8.11.3、10.15.0和12.6.0上进行了测试

它在所有测试版本上都具有相同的行为。

代码审查 在查看GitHub上的完整代码并在Windows 10上使用节点v10.16.0运行它之后,它看起来像是在
AsyncTracker中返回的承诺。WaitCurrentAsyncOperations
从未解决过,这会阻止
main()
中的代码超越
Wait AsyncTracker.WaitCurrentAsyncOperations()零件

这解释了为什么
**33**
部分从未输出,以及
main()
然后(…)
回调从未打印出
Done
。所述承诺的解析方法被分配给
this.asyncOperationsWaitResolver
,但是(根据当前实现),只有当
this.asyncOperation
集中没有更多承诺时,才会调用它。如下面的第一控制台输出所示,情况并非如此

问题再生产 我稍微修改了代码以处理
process.on
index.js
脚本末尾的事件

process.on('exit',()=>{console.log('processexited')});
process.on('uncaughtException',(err)=>{console.error(err&&err.stack | | err)});
process.on('unhandledRejection',(reason,promise)=>{console.error('unhandledRejection at:',promise',reason:',reason:',reason});
process.on('multipleResolved',(type,promise,reason)=>{console.error(type,promise,reason)});
退出回调是唯一被调用的回调。**22**标记后的控制台输出为:

**22**
>>>>>>>单元格已结束,异步操作跟踪已禁用,当前有3个异步操作正在进行。
等待操作完成,创建承诺。
!! 还有3个异步操作:
#9-承诺。
#10-承诺。
#11-承诺。
%%已删除异步操作#9
!! 还有2个异步操作:
#10-承诺。
#11-承诺。
进程退出
解决方案 问题是由
removeAsyncOperation(asyncId)
方法中的键入错误引起的。 而不是:

removeAsyncOperation(异步ID){
// ...
if(this.asyncOperationsWaitingResolver&&this.asyncOperations.size=0){
//...
}
}
} 
这样,只要队列中有承诺,就可以解析承诺

在对
async tracker.js
进行上述更改后,应用程序的行为与预期一致,并生成以下输出:

**22**
>>>>>>>单元格已结束,异步操作跟踪已禁用,当前有3个异步操作正在进行。
等待操作完成,创建承诺。
!! 还有3个异步操作:
#9-承诺。
#10-承诺。
#11-承诺。
%%已删除异步操作#9
!! 还有2个异步操作:
#10-承诺。
#11-承诺。
%%解析异步操作承诺!
** 33 **
多恩
%%已删除异步操作#10
!! 还有1个异步操作:
#11-承诺。
%%已删除异步操作#11
!! 剩余0个异步操作:
进程退出

好的,我现在有答案了。我会继续更新这个,因为我更好地理解我造成的这个问题

我的回答还没有完全解释Node.js的操作方式,但它是一种解决方案

我的代码试图等待在一段代码中发生的任意异步操作完成。在我的代码示例中,异步操作的跟踪发生在
main
函数中,而
then
catch
处理程序发生在
main
函数之外。我的理论是,被跟踪的异步操作被永远不会执行的代码“保持活动”:导致异步操作完成的代码永远不会执行

我通过删除
然后
catch
回调发现了这一点,这使我的程序正常终止

所以我的工作原理是,我导致了某种Node.js promis
const asyncTracker = new AsyncTracker();
asyncTracker.init();
asyncTracker.enableTracking(); // Enable async operation tracking.

// ---- Async operations created from here on are tracked.

// The simplest async operation that causes this problem.
// If you comment out this code the program completes normally.
await Promise.resolve(); 

// ---  Now we disable tracking of async operations, 
// then wait for all current operations to complete before continuing.

// Disable async tracking and wait.
await asyncTracker.awaitCurrentAsyncOperations();