无法获得承诺函数的原始返回值

时间:2019-02-20 20:57:35

标签: javascript node.js express asynchronous promise

下面的代码可以工作,但是不能保证。

const express = require('express');
function listenAndReturnServer() {
    app = express();

    console.log('Before listen');
    const server = app.listen(8001, function() {
        console.log('Now listening');
    });
    console.log('After listen');
    return server;
}
const server = listenAndReturnServer();
console.log('Doing some stuff');
console.log(typeof(server));

它输出以下内容:

Before listen
After listen
Doing some stuff
object
Now listening

我要解决的问题是我想用依赖于服务器运行的代码替换“执行一些操作”日志,并调用了listen回调(显示“ Now Listening”)。如您所见,“正在监听”之前会记录“做一些事情”。进来util.promisify。

我已将以上内容更改为以下内容。

const express = require('express');
const util = require('util');
async function listenAndReturnServer() {
    app = express();

    console.log('Before listen');
    const listenAsync = util.promisify(app.listen);
    const server = await listenAsync(8001).then(() => {
        console.log('Now listening');
    });
    console.log('After listen');
    return server;
}
async function main() {
    const server = await listenAndReturnServer();
    console.log('Doing some stuff');
    console.log(typeof(server));
}
main();

这一次,事物至少以正确的顺序登录。

Before listen
Now listening
After listen
undefined
Doing some stuff

现在有一个新问题:server的类型未定义。实际上,我需要它是原始的Server对象,因此我可以关闭服务器。

任何人都可以识别这里发生的事情以及如何获得想要的行为吗?

1 个答案:

答案 0 :(得分:2)

[正在重写,因为这里发生了很多事情]

在这段代码上工作了一段时间之后,我意识到存在以下几个问题/错误的假设:

const express = require('express');
const util = require('util');
async function listenAndReturnServer() {
    app = express();

    console.log('Before listen');

// ISSUE #1: `listenAsync` is not bound to `app` here.  This
// risks errors where Express may rely on `this` internally.
//
// ISSUE #2: Promisify is intended to operate on methods that
// take node-style callbacks, where the *callback* receives
// (err, arg0, arg1, ...) arguments, with the promise
// resolving to the 2nd argument (arg0).
// In the case of listen(), though, the callback isn't expected
// to be node-style(!), so doesn't receive any arguments
// (see https://nodejs.org/api/net.html#net_server_listen)
    const listenAsync = util.promisify(app.listen);

// ISSUE #3: `await` and `then()` serve similar purposes.
// Using them together like this is a little weird.
// You should probably just `await`, then do your console.log
// afterwards.      
    const server = await listenAsync(8001).then(() => {
        console.log('Now listening');
    });
    console.log('After listen');
    return server;
}
async function main() {
    const server = await listenAndReturnServer();
    console.log('Doing some stuff');
    console.log(typeof(server));
}
main();

如果您要对此进行承诺以使其与async配合使用,则这样简单地创建一个Promise可能会更简单:

const express = require('express');

const app = express();

// Note: Not writing this as an `async` function because none
// of the APIs we're using return promises that can be `await`ed,
// and we explicitly return a promise
function main() {
  return new Promise(function(resolve, reject) {
    // Resolve to the server instance if listen() succeeds
    // Note: `server` here is Node's `http` server, not the Express instance
    const server = app.listen(8001, () => resolve(server));

    // Otherwise reject promise if there's an error
    server.on('error', reject);
  });
}

main()
  .then(server => console.log(server))
  .catch(err => console.error(err));