以下の例のような単純なコールバックを使用する場合:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
非同期/待機を使用するように関数を変更するにはどうすればよいですか?具体的には、「someEvent」が一度だけ呼び出されることが保証されていると仮定すると、コールバックが実行されるまで戻らない非同期関数である関数テストを希望します:
async test() {
return await api.on( 'someEvent' );
}
async/await
は魔法ではありません。非同期関数は、Promiseをアンラップできる関数です。そのため、Promiseを機能させるにはapi.on()
が必要です。このようなもの:
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.
}
しかし、非同期関数もPromiseを返すため、それも嘘です。したがって、実際に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);
});
}
上記の関数はまだ何も返しません。 Promise
に渡されたresponse
のcallback
を返すようにするには、次のようにします。
const util = require('util');
const asyncFunction = util.promisify(voidFunction);
これで、実際にawait
the callback
を作成できます。
async function test() {
return await asyncFunction(args);
}
util.promisify
を使用する場合のいくつかのルール
callback
は、promisify
になる関数の最後の引数でなければなりません(err, res) => {...}
の形式である必要があります面白いことに、実際にcallback
とは何かを明確に記述する必要はありません。
あなたはコールバックなしでこれを達成することができます、ここで私がこれをする方法コールバックの代わりにpromise async awaitを使用してください。また、ここでエラーを処理する2つの方法を示しました
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');
}
引数の数は可変です。