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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46933801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:03:04  来源:igfitidea点击:

How do i wrap a callback with async await?

javascriptnode.jsecmascript-6ecmascript-2017

提问by Tiago Bértolo

My function resolves a promise that resolves as soon as the http server starts. This is my code:

我的函数解决了一个承诺,该承诺在 http 服务器启动后立即解决。这是我的代码:

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?

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

采纳答案by guest271314

Include asyncbefore the function declaration and awaitthe Promiseconstructor. Though note, you would essentially be adding code to the existing pattern. awaitconverts a value to a Promise, though the code at Question already uses Promiseconstructor.

包括async函数声明和之前awaitPromise构造。不过请注意,您实际上是在向现有模式添加代码。await将一个值转换为 a 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));

回答by JoshWillik

Creating a new Promiselike the other answers suggest works fine in this case, but as a general rule, util.promisifycan 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完成。

回答by Damaged Organic

This is something I've stumbled upon when while trying to make httpserver listenfunction truly promisified. Biggest problem is not to resolve on listeningcallback, but to handle the errors on startup.

这是我在尝试使http服务器listen功能真正实现时偶然发现的。最大的问题不是解决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, netor derived http/https, are EventEmitterinstances, which means no errors are thrown. Instead, they are emitted as the errorevent.

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

So, considering all of the above, correct implementation of promisified server listenfunction is as follows:

因此,考虑到以上所有因素,promisified serverlisten功能的正确实现如下:

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 listenmethod will either start server or throw catchable error.

这样就可以保证该listen方法要么启动服务器,要么抛出可捕获的错误。

回答by Kejt

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

我相信这样的事情

回答by 538ROMEO

I created a basic util that may not be the most proper way to dobut is way more readableIMO:

我创建了一个基本的实用程序,它可能不是最合适的方法,但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 carrefulif your promise may return undefined values has the function will run forever (but this will not crash).

这是基本概念。但是,如果您的承诺可能返回未定义的值,则要小心,因为该函数将永远运行(但这不会崩溃)。