非同期機能、機能 ES2017で、使用してコードを見て同期非同期メイク約束(非同期コードの特定の形態)とawait
キーワードを。また、以下のコード例では、async / await関数を表すキーワードのasync
前のキーワードに注意してくださいfunction
。await
キーワードは、キーワードが前に付けられた関数内になければ機能しませんasync
。現在、これに例外はありません。つまり、トップレベルの待機は機能しません(トップレベルの待機は、関数の外での待機を意味します)。トップレベルの提案await
がありますが。
ES2017は、2017年6月27日にJavaScriptの標準として承認(つまり、最終決定)されました。非同期待機はブラウザーで既に機能している可能性がありますが、そうでない場合でも、babelやtraceurなどのJavaScriptトランスパイラーを使用して機能を使用できます。Chrome 55は非同期機能を完全にサポートしています。したがって、新しいブラウザを使用している場合は、以下のコードを試すことができる場合があります。
ブラウザーの互換性については、kangaxのes2017互換性表を参照してください。
以下は、非同期await関数の例です。 doAsync
これは、3つの1秒のポーズを取り、開始時間からの各ポーズの後の時間差を出力します。
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
async function doAsync () {
var start = Date.now(), time;
console.log(0);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
}
doAsync();
awaitキーワードがpromise値(この場合、promise値は関数doSomethingAsyncによって返される値です)の前に配置されると、awaitキーワードは関数呼び出しの実行を一時停止しますが、他の関数は一時停止せず、続行しますpromiseが解決するまで他のコードを実行します。promiseが解決されると、promiseの値がラップ解除されます。awaitおよびpromise式は、ラップ解除された値に置き換えられていると考えることができます。
したがって、awaitは一時停止を待ってから値をアンラップしてから残りの行を実行するので、配列で待機している時間差を収集して配列を出力する次の例のように、forループや内部関数呼び出しで使用できます。
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this calls each promise returning function one after the other
async function doAsync () {
var response = [];
var start = Date.now();
// each index is a promise returning function
var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
for(var i = 0; i < promiseFuncs.length; ++i) {
var promiseFunc = promiseFuncs[i];
response.push(await promiseFunc() - start);
console.log(response);
}
// do something with response which is an array of values that were from resolved promises.
return response
}
doAsync().then(function (response) {
console.log(response)
})
非同期関数自体がプロミスを返すので、上記のように、または別の非同期await関数内でチェーンのプロミスとして使用できます。
上記の関数は、Promise.allを使用してリクエストを同時に送信したい場合、別のリクエストを送信する前に各応答を待機します。
// no change
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
// no change
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async function doAsync () {
var start = Date.now();
// we are now using promise all to await all promises to settle
var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
return responses.map(x=>x-start);
}
// no change
doAsync().then(function (response) {
console.log(response)
})
promiseが拒否する可能性がある場合は、try catchでラップするか、try catchをスキップして、非同期/待機関数のcatch呼び出しにエラーを伝播させることができます。特にNode.jsでは、promiseエラーを未処理のままにしないように注意する必要があります。以下は、エラーがどのように機能するかを示すいくつかの例です。
function timeoutReject (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
}, time)
})
}
function doErrorAsync () {
return timeoutReject(1000);
}
var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);
async function unpropogatedError () {
// promise is not awaited or returned so it does not propogate the error
doErrorAsync();
return "finished unpropogatedError successfully";
}
unpropogatedError().then(log).catch(logErr)
async function handledError () {
var start = Date.now();
try {
console.log((await doErrorAsync()) - start);
console.log("past error");
} catch (e) {
console.log("in catch we handled the error");
}
return "finished handledError successfully";
}
handledError().then(log).catch(logErr)
// example of how error propogates to chained catch method
async function propogatedError () {
var start = Date.now();
var time = await doErrorAsync() - start;
console.log(time - start);
return "finished propogatedError successfully";
}
// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)
ここに行くと、ECMAScriptの今後のバージョンの完成した提案を見ることができます。
ES2015(ES6)だけで使用できるこの代替手段は、ジェネレーター関数をラップする特別な関数を使用することです。ジェネレータ関数には、周囲の関数でawaitキーワードを複製するために使用できるyieldキーワードがあります。yieldキーワードとジェネレーター関数はより一般的な目的であり、非同期await関数が実行することよりも多くのことを実行できます。非同期を複製するために使用できるジェネレーター関数ラッパーが必要な場合は、co.jsをチェックしてください。。ちなみに、coの関数は非同期のawait関数とほぼ同じで、promiseを返します。正直なところ、現時点ではブラウザーの互換性はジェネレーター関数と非同期関数の両方でほぼ同じなので、非同期待機機能だけが必要な場合は、co.jsなしの非同期関数を使用する必要があります。
IEを除くすべての主要な現在のブラウザー(Chrome、Safari、およびEdge)の非同期機能(2017年時点)のブラウザーサポートは、実際にはかなり良好です。