我如何使用异步等待包装回调?

How do i wrap a callback with async await?

我的函数 returns 一个承诺,一旦 http 服务器启动就会解析。这是我的代码:

function start() {
    return new Promise((resolve, reject) {
        this.server = Http.createServer(app);
        this.server.listen(port, () => {
            resolve();
        });
    })
}

如何将启动函数转换为 async/await?

const doRequest = () => new Promise((resolve, reject) {
        this.server = Http.createServer(app);
        this.server.listen(port, () => {
            resolve();
        });
    })

async function start() {
 await doRequest()
}

我相信是这样的

在函数声明之前包括 asyncawait Promise 构造函数。请注意,您实际上是在向现有模式添加代码。 await 将值转换为 Promise,尽管问题处的代码已经使用了 Promise 构造函数。

async function start() {
    let promise = await new Promise((resolve, reject) => {
        this.server = Http.createServer(app);
        this.server.listen(port, () => {
            resolve();
        });
    })
    .catch(err => {throw err});

    return promise
}

start()
.then(data => console.log(data))
.catch(err => console.error(err));

像其他答案建议的那样创建一个 new Promise 在这种情况下效果很好,但作为一般规则,util.promisify 可以阻止您多次编写相同的内容。

因此您可以改为执行以下操作:(node.js v8.0.0+)

const util = require('util');
async function start() {
    let server = Http.createServer(app);
    await util.promisify(server.listen.bind(server))(port);
}

util.promisify(some_function) 采用一个通常接受回调的函数,returns 这个函数的一个新的包装版本,而不是 returns 一个承诺。

更多解释步骤:

let server = Http.createServer(app);
// .bind() is needed so that .listen() keeps the correct `this` context when it is called.
// If your function does not require any specific context, leave off .bind()
let listen_promise = util.promisify(server.listen.bind(server));
await listen_promise(port);

可以使用 bluebird 来完成更高级的承诺。

这是我在尝试使 http 服务器 listen 功能真正实现时偶然发现的。最大的问题不是解决 listening 回调,而是处理启动时的错误。

包装在 Promise 中并尝试 catch(如其他答案所建议的那样)或 try-catch 块不会有任何效果,因为任何 Node.js 服务器、net 或派生http/httpsEventEmitter 个实例,这意味着不会抛出任何错误。相反,它们作为 error 事件发出。

因此,考虑到以上所有因素,promisified server listen 函数的正确实现如下:

const { createServer } = require('http');

const server = createServer();

const listen = async (port, host) => {
  return new Promise((resolve, reject) => {
    const listeners = {};

    listeners.onceError = (error) => {
      server.removeListener('listening', listeners.onceListening);
      reject(error);
    };

    listeners.onceListening = () => {
      server.removeListener('error', listeners.onceError);
      resolve();
    };

    server
      .prependOnceListener('error', listeners.onceError)
      .prependOnceListener('listening', listeners.onceListening);

    server.listen(port, host);
  });
}

处理程序内部的拒绝和解决调用被添加到侦听器堆栈的顶部,它们相互抵消 - 谁先触发。

这样可以保证 listen 方法将启动服务器或抛出可捕获的错误。

我创建了一个基本实用程序,可能不是最合适的方法,但更具可读性 IMO:

// async timout util
const timeout = async ms => new Promise(res => setTimeout(res, ms));

async function start() {
    let output;

    this.server = Http.createServer(app);
    this.server.listen(port, () => {
        output = true; // or can be any data that you want to return
    });
    while (output === undefined) await timeout(10);
    return output;
}

这是基本概念。然而 carreful 如果你的承诺可能 return undefined values has the function will 运行 forever (but this will not crash).