【问题标题】:Cannot get original return value of promisified function无法获得承诺函数的原始返回值
【发布时间】:2019-07-14 15:53:21
【问题描述】:

下面的代码有效,但没有被承诺。

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

我要解决的问题是,我想用取决于正在运行的服务器的代码替换“做一些事情”日志,并且已经调用了侦听回调(打印“正在侦听”)。如您所见,在“现在收听”之前记录了“做一些事情”。 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 对象,所以我可以关闭服务器。

谁能确定这里发生了什么,以及如何获得我想要的行为?

【问题讨论】:

  • 这里函数的返回值是多少? .then(() => { console.log('Now listening'); }); 这就是 Promise 将要解决的问题;这就是将分配给const server
  • 我明白了。我是新的承诺,所以这可以解释我的全部问题。如您所见,没有返回值。我如何在您发布的代码 sn-p 中的未命名函数的上下文中获取原始 app.listen 的返回值?这是传递给 then() 的参数吗?
  • 一种方法是.then((value) => { console.log('Now listening'); return value });。一些 Promise 库提供了一个函数来挂钩到 Promise 链而不会中断/更改它,例如 Bluebird#tap()。但是,海事组织。对于这种情况,您已经从下面的 broofa 那里得到了最佳答案。
  • @Thomas 我试过了,value 未定义。
  • 这听起来好像出了点问题:util.promisify(app.listen);答案中的代码似乎有同样的问题这一事实只是鼓励了这种假设。我最好的猜测是this 不见了,但我现在没有时间检查。试试util.promisify(app.listen.bind(app))await listenAsync.call(app, 8001)(不在一起)

标签: javascript node.js express asynchronous promise


【解决方案1】:

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

在研究了这段代码之后,我意识到有几个问题/错误的假设,如下:

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();

如果您想 Promisify 使其与 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));

【讨论】:

  • 我还有一个问题,就是您发布的解决方案server 没有定义。
  • 忽略我之前写的。用代码和 cmets 更新答案,你知道,实际测试我写的代码。 :-p
猜你喜欢
  • 2022-08-09
  • 2017-07-21
  • 2018-08-25
  • 2019-02-02
  • 2014-07-05
  • 2019-01-23
  • 2020-09-21
  • 1970-01-01
  • 2016-10-24
相关资源
最近更新 更多