如何"await"回调到return?
How to "await" for a callback to return?
使用如下例所示的简单回调时:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
如何将函数更改为使用 async / await?具体来说,假设 'someEvent' 保证被调用一次且仅调用一次,我希望函数测试是一个异步函数,在执行回调之前不会 return 例如:
async test() {
return await api.on( 'someEvent' );
}
async/await
不是魔法。异步函数是一个可以为您解包 Promise 的函数,因此您需要 api.on()
到 return 一个 Promise 才能工作。像这样:
function apiOn(event) {
return new Promise(resolve => {
api.on(event, response => resolve(response));
});
}
然后
async function test() {
return await apiOn( 'someEvent' ); // await is actually optional here
// you'd return a Promise either way.
}
但这也是一个谎言,因为异步函数也 return 承诺自己,所以你不会真正从 test()
中获得价值,而是一个价值的 Promise ,您可以像这样使用它:
async function whatever() {
// snip
const response = await test();
// use response here
// snip
}
令人恼火的是,没有一个简单的解决方案,包装 return new Promise(...)
很麻烦,但我找到了一个使用 util.promisify
的不错的解决方法(实际上它也有点做同样的包装, 只是看起来更好)。
function voidFunction(someArgs, callback) {
api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {
callback(null, response_we_need);
});
}
上面的函数 return 还没有任何作用。我们可以通过以下方式使 return 成为 callback
中传递的 response
的 Promise
:
const util = require('util');
const asyncFunction = util.promisify(voidFunction);
现在我们实际上可以 await
callback
。
async function test() {
return await asyncFunction(args);
}
使用时的一些规则util.promisify
callback
必须是将成为 promisify
的函数的最后一个参数
- 假定的回调必须采用
(err, res) => {...}
的形式
有趣的是我们不需要特别写出 callback
到底是什么。
你可以在没有回调的情况下实现这一点,在这里使用 promise async await 而不是回调,我将如何做到这一点。在这里我还说明了两种处理错误的方法
clickMe = async (value) => {
// begin to wait till the message gets here;
let {message, error} = await getMessage(value);
// if error is not null
if(error)
return console.log('error occured ' + error);
return console.log('message ' + message);
}
getMessage = (value) => {
//returning a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// if passed value is 1 then it is a success
if(value == 1){
resolve({message: "**success**", error: null});
}else if (value == 2){
resolve({message: null, error: "**error**"});
}
}, 1000);
});
}
clickWithTryCatch = async (value) => {
try{
//since promise reject in getMessage2
let message = await getMessage2(value);
console.log('message is ' + message);
}catch(e){
//catching rejects from the promise
console.log('error captured ' + e);
}
}
getMessage2 = (value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(value == 1)
resolve('**success**');
else if(value == 2)
reject('**error**');
}, 1000);
});
}
<input type='button' value='click to trigger for a value' onclick='clickMe(1)' />
<br/>
<input type='button' value='click to trigger an error' onclick='clickMe(2)' />
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(1)'/>
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(2)'/>
async/await 很神奇。您可以创建一个函数 asPromise
来处理这种情况:
function asPromise(context, callbackFunction, ...args) {
return new Promise((resolve, reject) => {
args.push((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
if (context) {
callbackFunction.call(context, ...args);
} else {
callbackFunction(...args);
}
});
}
然后在需要时使用它:
async test() {
return await this.asPromise(this, api.on, 'someEvent');
}
args 的数量是可变的。
const getprice = async () => {
return await new Promise((resolve, reject) => {
binance.prices('NEOUSDT', (error, ticker) => {
if (error) {
reject(error)
} else {
resolve(ticker);
}
});
})}
router.get('/binanceapi/price', async function (req, res, next) {
res.send(await binanceAPI.getprice());});
使用如下例所示的简单回调时:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
如何将函数更改为使用 async / await?具体来说,假设 'someEvent' 保证被调用一次且仅调用一次,我希望函数测试是一个异步函数,在执行回调之前不会 return 例如:
async test() {
return await api.on( 'someEvent' );
}
async/await
不是魔法。异步函数是一个可以为您解包 Promise 的函数,因此您需要 api.on()
到 return 一个 Promise 才能工作。像这样:
function apiOn(event) {
return new Promise(resolve => {
api.on(event, response => resolve(response));
});
}
然后
async function test() {
return await apiOn( 'someEvent' ); // await is actually optional here
// you'd return a Promise either way.
}
但这也是一个谎言,因为异步函数也 return 承诺自己,所以你不会真正从 test()
中获得价值,而是一个价值的 Promise ,您可以像这样使用它:
async function whatever() {
// snip
const response = await test();
// use response here
// snip
}
令人恼火的是,没有一个简单的解决方案,包装 return new Promise(...)
很麻烦,但我找到了一个使用 util.promisify
的不错的解决方法(实际上它也有点做同样的包装, 只是看起来更好)。
function voidFunction(someArgs, callback) {
api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {
callback(null, response_we_need);
});
}
上面的函数 return 还没有任何作用。我们可以通过以下方式使 return 成为 callback
中传递的 response
的 Promise
:
const util = require('util');
const asyncFunction = util.promisify(voidFunction);
现在我们实际上可以 await
callback
。
async function test() {
return await asyncFunction(args);
}
使用时的一些规则util.promisify
callback
必须是将成为promisify
的函数的最后一个参数
- 假定的回调必须采用
(err, res) => {...}
的形式
有趣的是我们不需要特别写出 callback
到底是什么。
你可以在没有回调的情况下实现这一点,在这里使用 promise async await 而不是回调,我将如何做到这一点。在这里我还说明了两种处理错误的方法
clickMe = async (value) => {
// begin to wait till the message gets here;
let {message, error} = await getMessage(value);
// if error is not null
if(error)
return console.log('error occured ' + error);
return console.log('message ' + message);
}
getMessage = (value) => {
//returning a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// if passed value is 1 then it is a success
if(value == 1){
resolve({message: "**success**", error: null});
}else if (value == 2){
resolve({message: null, error: "**error**"});
}
}, 1000);
});
}
clickWithTryCatch = async (value) => {
try{
//since promise reject in getMessage2
let message = await getMessage2(value);
console.log('message is ' + message);
}catch(e){
//catching rejects from the promise
console.log('error captured ' + e);
}
}
getMessage2 = (value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(value == 1)
resolve('**success**');
else if(value == 2)
reject('**error**');
}, 1000);
});
}
<input type='button' value='click to trigger for a value' onclick='clickMe(1)' />
<br/>
<input type='button' value='click to trigger an error' onclick='clickMe(2)' />
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(1)'/>
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(2)'/>
async/await 很神奇。您可以创建一个函数 asPromise
来处理这种情况:
function asPromise(context, callbackFunction, ...args) {
return new Promise((resolve, reject) => {
args.push((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
if (context) {
callbackFunction.call(context, ...args);
} else {
callbackFunction(...args);
}
});
}
然后在需要时使用它:
async test() {
return await this.asPromise(this, api.on, 'someEvent');
}
args 的数量是可变的。
const getprice = async () => {
return await new Promise((resolve, reject) => {
binance.prices('NEOUSDT', (error, ticker) => {
if (error) {
reject(error)
} else {
resolve(ticker);
}
});
})}
router.get('/binanceapi/price', async function (req, res, next) {
res.send(await binanceAPI.getprice());});