简体   繁体   English

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

[英]How do i wrap a callback with async await?

My function returns a promise that resolves as soon as the http server starts.我的函数返回一个承诺,该承诺在 http 服务器启动后立即解决。 This is my code:这是我的代码:

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

How do I convert the start function to async/await?如何将 start 函数转换为 async/await?

Include async before the function declaration and await the Promise constructor.在函数声明之前包含asyncawait Promise构造函数。 Though note, you would essentially be adding code to the existing pattern.请注意,您实际上是在向现有模式添加代码。 await converts a value to a Promise , though the code at Question already uses Promise constructor. await将值转换为Promise ,尽管 Question 中的代码已经使用了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));

Creating a new Promise like the other answers suggest works fine in this case, but as a general rule, util.promisify can stop you from writing the same thing many times.在这种情况下,像其他答案所建议的那样创建一个new Promise工作正常,但作为一般规则, util.promisify可以阻止您多次编写相同的内容。

So you can do something like this instead: (node.js v8.0.0+)所以你可以做这样的事情:(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) takes a function which normally accepts a callback, and returns a new, wrapped version of this function that instead returns a promise. util.promisify(some_function)接受一个通常接受回调的函数,并返回此函数的新包装版本,而不是返回承诺。

With more explained steps:有更多解释的步骤:

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

More advanced promisification can be done with bluebird .更高级的promisification 可以用bluebird完成。

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

async function start() {
 await doRequest()
}

something like this I believe我相信这样的事情

This is something I've stumbled upon when while trying to make http server listen function truly promisified.这是我在尝试使http服务器listen功能真正承诺时偶然发现的。 Biggest problem is not to resolve on listening callback, but to handle the errors on startup.最大的问题不是解决listening回调,而是处理启动时的错误。

Wrapping in Promise and attempt to catch (as other answers suggest) or try-catch block won't have any effect, because any Node.js server, net or derived http / https , are EventEmitter instances, which means no errors are thrown.包装在 Promise 中并尝试catch (如其他答案所建议的)或 try-catch 块不会产生任何效果,因为任何 Node.js 服务器、 net或派生的http / https都是EventEmitter实例,这意味着不会引发错误。 Instead, they are emitted as the error event.相反,它们作为error事件发出。

So, considering all of the above, correct implementation of promisified server listen function is as follows:因此,考虑到以上所有因素,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);
  });
}

Reject and resolve calls inside handlers are prepended to the top of the listeners stack, and they mutually cancel each other - whoever fires first.处理程序中的拒绝和解决调用被添加到侦听器堆栈的顶部,并且它们相互抵消 - 谁先触发。

That way it's guaranteed that listen method will either start server or throw catchable error.这样可以保证listen方法要么启动服务器,要么抛出可捕获的错误。

I created a basic util that may not be the most proper way to do but is way more readable IMO:我创建了一个基本的实用程序,它可能不是最合适的方法,但在 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;
}

This is the basic concept.这是基本概念。 However be carreful if your promise may return undefined values has the function will run forever (but this will not crash).但是,如果您的承诺可能返回未定义的值,则要小心,因为该函数将永远运行(但这不会崩溃)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM