簡體   English   中英

我如何用異步等待包裝回調?

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

我的函數返回一個承諾,該承諾在 http 服務器啟動后立即解決。 這是我的代碼:

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

如何將 start 函數轉換為 async/await?

在函數聲明之前包含asyncawait Promise構造函數。 請注意,您實際上是在向現有模式添加代碼。 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));

在這種情況下,像其他答案所建議的那樣創建一個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)接受一個通常接受回調的函數,並返回此函數的新包裝版本,而不是返回承諾。

有更多解釋的步驟:

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

更高級的promisification 可以用bluebird完成。

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

async function start() {
 await doRequest()
}

我相信這樣的事情

這是我在嘗試使http服務器listen功能真正承諾時偶然發現的。 最大的問題不是解決listening回調,而是處理啟動時的錯誤。

包裝在 Promise 中並嘗試catch (如其他答案所建議的)或 try-catch 塊不會產生任何效果,因為任何 Node.js 服務器、 net或派生的http / https都是EventEmitter實例,這意味着不會引發錯誤。 相反,它們作為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;
}

這是基本概念。 但是,如果您的承諾可能返回未定義的值,則要小心,因為該函數將永遠運行(但這不會崩潰)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM