Mer*_*erc 4 node.js promise async-await es6-promise
我在 node 的 promisify() 函数中发现了一个奇怪的行为,我无法弄清楚它为什么这样做。
考虑以下脚本:
#!/usr/bin/env node
/**
* Module dependencies.
*/
var http = require('http')
var promisify = require('util').promisify
;(async () => {
try {
// UNCOMMENT THIS, AND NODE WILL QUIT
// var f = function () { return 'Straight value' }
// var fP = promisify(f)
// await fP()
/**
* Create HTTP server.
*/
var server = http.createServer()
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(3000)
server.on('error', (e) => { console.log('Error:', e); process.exit() })
server.on('listening', () => { console.log('Listening') })
} catch (e) {
console.log('ERROR:', e)
}
})()
console.log('OUT OF THE ASYNC FUNCTION')
Run Code Online (Sandbox Code Playgroud)
这是一个简单的自调用函数,用于启动节点服务器。这很好。
现在...如果您取消注释“UNCOMMENT THIS”下的行,节点将退出而不运行服务器。
我知道我在一个不调用回调但返回一个值的函数上使用 promisify() 。所以,我知道这本身就是一个问题。
但是......为什么节点只是退出......?
这真的很难调试——尤其是当你有比小脚本更复杂的东西时。
如果将函数定义更改为实际调用回调的内容:
var f = function (cb) { setTimeout( () => { return cb( null, 'Straight value') }, 2000) }
Run Code Online (Sandbox Code Playgroud)
一切都按预期工作......
更新
极大的简化:
function f () {
return new Promise(resolve => {
console.log('AH')
})
}
f().then(() => {
console.log('Will this happen...?')
})
Run Code Online (Sandbox Code Playgroud)
只会打印“AH”!
在非回调函数上调用 promisify():“有趣”的结果是 node. 为什么?
因为你允许 node.js 无所事事地进入事件循环。由于没有实时的异步操作,也没有更多的代码要运行,node.js 意识到没有其他事情可做,也没有办法运行其他任何东西,所以它退出了。
当你点击await并且 node.js 回到事件循环时,没有任何东西保持 node.js 运行,所以它退出了。没有计时器或打开的套接字或任何保持 node.js 运行的类型的东西,所以 node.js 自动退出检测逻辑说没有其他事情要做,所以它退出。
因为 node.js 是一个事件驱动的系统,如果你的代码返回到事件循环并且没有任何类型的异步操作(打开套接字、侦听服务器、定时器、文件 I/O 操作、其他硬件侦听器等) ...),则没有任何运行可以在事件队列中插入任何事件,并且队列当前为空。因此,node.js 意识到永远不可能在此应用程序中运行更多代码,因此它退出。这是 node.js 内置的自动行为。
内部真正的异步操作fp()将具有某种套接字或计时器或保持进程运行的打开状态。但是因为你的是假的,所以没有任何东西可以保持 node.js 运行。
如果在 中放置setTimeout()1 秒f(),您将看到进程退出发生在 1 秒后。所以,进程退出与promise无关。这与您已经返回到事件循环这一事实有关,但您还没有启动任何可以保持 node.js 运行的操作。
或者,如果将 asetInterval()放在 async 函数的顶部,您将同样发现该进程不会退出。
因此,如果您这样做,也会类似地发生这种情况:
var f = function () { return 'Straight value' }
var fP = promisify(f);
fP().then(() => {
// start your server here
});
Run Code Online (Sandbox Code Playgroud)
或这个:
function f() {
return new Promise(resolve => {
// do nothing here
});
}
f().then(() => {
// start your server here
});
Run Code Online (Sandbox Code Playgroud)
问题不在于promisify()操作。这是因为您正在等待一个不存在的异步操作,因此 node.js 无事可做,它注意到无事可做,所以它会自动退出。使用.then()处理程序公开承诺并不能保持 node.js 运行。而是需要一些活动的异步操作(计时器、网络套接字、侦听服务器、正在进行的文件 I/O 操作等...)来保持 node.js 运行。
在这种特殊情况下,node.js 本质上是正确的。你的承诺永远不会解决,没有其他东西排队运行,因此你的服务器永远不会启动,你的应用程序中的其他代码永远不会运行,因此继续运行实际上没有用。您的代码无事可做,也无法真正做其他任何事情。
如果将函数定义更改为实际调用回调的内容:
那是因为你使用了一个计时器,所以 node.js 在等待 promise 解决时有一些实际的事情要做。没有.unref()调用它的正在运行的计时器将阻止自动退出。
值得一读:node.js 进程如何知道何时停止?
仅供参考,您可以“关闭”或“绕过”node.js 自动退出逻辑,只需将其添加到启动代码的任何位置即可:
// timer that fires once per day
let foreverInterval = setInterval(() => {
// do nothing
}, 1000 * 60 * 60 * 24);
Run Code Online (Sandbox Code Playgroud)
这总是给 node.js 一些事情要做,所以它永远不会自动退出。然后,当您确实希望您的进程退出时,您可以调用clearInterval(foreverInterval)或仅使用process.exit(0).
| 归档时间: |
|
| 查看次数: |
539 次 |
| 最近记录: |