我如何使用异步等待包装回调?
How do i wrap a callback with async await?
我的函数 returns 一个承诺,一旦 http 服务器启动就会解析。这是我的代码:
function start() {
return new Promise((resolve, reject) {
this.server = Http.createServer(app);
this.server.listen(port, () => {
resolve();
});
})
}
如何将启动函数转换为 async/await?
const doRequest = () => new Promise((resolve, reject) {
this.server = Http.createServer(app);
this.server.listen(port, () => {
resolve();
});
})
async function start() {
await doRequest()
}
我相信是这样的
在函数声明之前包括 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));
像其他答案建议的那样创建一个 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)
采用一个通常接受回调的函数,returns 这个函数的一个新的包装版本,而不是 returns 一个承诺。
更多解释步骤:
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 来完成更高级的承诺。
这是我在尝试使 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;
}
这是基本概念。然而 carreful 如果你的承诺可能 return undefined values has the function will 运行 forever (but this will not crash).
我的函数 returns 一个承诺,一旦 http 服务器启动就会解析。这是我的代码:
function start() {
return new Promise((resolve, reject) {
this.server = Http.createServer(app);
this.server.listen(port, () => {
resolve();
});
})
}
如何将启动函数转换为 async/await?
const doRequest = () => new Promise((resolve, reject) {
this.server = Http.createServer(app);
this.server.listen(port, () => {
resolve();
});
})
async function start() {
await doRequest()
}
我相信是这样的
在函数声明之前包括 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));
像其他答案建议的那样创建一个 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)
采用一个通常接受回调的函数,returns 这个函数的一个新的包装版本,而不是 returns 一个承诺。
更多解释步骤:
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 来完成更高级的承诺。
这是我在尝试使 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;
}
这是基本概念。然而 carreful 如果你的承诺可能 return undefined values has the function will 运行 forever (but this will not crash).