web-dev-qa-db-fra.com

Comment envelopper un rappel avec async attendre?

Ma fonction résout une promesse résolue dès le démarrage du serveur http. Ceci est mon code:

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

Comment puis-je convertir la fonction de démarrage en asynchrone/wait? 

7
Tiago Bértolo

Incluez async avant la déclaration de fonction et await le constructeur Promise. Notez que vous ajouterez essentiellement du code au modèle existant. await convertit une valeur en Promise, bien que le code de Question utilise déjà le constructeur 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

Créer un new Promise comme les autres réponses suggèrent que cela fonctionne très bien dans ce cas, mais en règle générale, util.promisify peut vous empêcher d'écrire la même chose plusieurs fois. 

Vous pouvez donc faire quelque chose comme ceci à la place: (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) prend une fonction qui accepte normalement un rappel et renvoie une nouvelle version encapsulée de cette fonction qui renvoie à la place une promesse.

Avec plus d'étapes expliquées:

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

Une promisification plus avancée peut être réalisée avec bluebird .

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

async function start() {
 await doRequest()
}

quelque chose comme ça je crois

2
Kejt

C’est quelque chose que j’ai trébuché en essayant de rendre http server listen vraiment promis. Le plus gros problème n'est pas de résoudre le rappel listening, mais de gérer les erreurs au démarrage.

Le fait d’emballer Promise et de tenter catch (comme le suggèrent d’autres réponses) ou le bloc try-catch n’aura aucun effet, car tout serveur Node.js, net ou dérivé http/https sont des instances EventEmitter, ce qui signifie qu’aucune erreur n’est renvoyée. Au lieu de cela, ils sont émis en tant qu'événement error.

Donc, compte tenu de tout ce qui précède, la bonne implémentation de la fonction de serveur listen promisifiée est la suivante:

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

Les appels rejetés et résolus à l'intérieur des gestionnaires sont ajoutés au début de la pile des écouteurs, et ils s'annulent mutuellement - celui qui déclenche le premier.

De cette façon, il est garanti que la méthode listen lancera le serveur ou jettera une erreur capturable.

1
Damaged Organic