it-swarm.com.ru

Как обернуть обратный вызов с асинхронным ожиданием?

Моя функция разрешает обещание, которое разрешается при запуске http-сервера. Это мой код:

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

Как мне преобразовать функцию запуска в async/await? 

7
Tiago Bértolo

Включите async перед объявлением функции и await конструктор 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));
7
guest271314

Создание 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);

Более сложное обещание можно сделать с помощью bluebird .

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

async function start() {
 await doRequest()
}

как-то так я верю

2
Kejt

Это то, на что я наткнулся, когда пытался сделать функцию http server listen по-настоящему многообещающей. Самая большая проблема заключается не в разрешении обратного вызова listening, а в обработке ошибок при запуске.

Обтекание в Promise и попытка catch (как предлагают другие ответы) или блок try-catch не будут иметь никакого эффекта, потому что любой сервер Node.js, net или производная http/https, являются экземплярами EventEmitter, что означает, что никаких ошибок не выдается. Вместо этого они отправляются как событие error.

Итак, учитывая все вышесказанное, правильная реализация функции 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 либо запустит сервер, либо выдаст перехватываемую ошибку.

1
Damaged Organic