JavaScriptのasync/await
6886 ワード
原文のリンク:https://segmentfault.com/a/1190000007535316?utm_source=tag-newest
asyncとawaitは何をしていますか?
いずれの名前も意味があります.まずは字面の意味から分かります.asyncは「非同期」の略で、awaitはasync waitの略と考えられます.だからasynctionは非同期であるということをよく理解しておくべきです.awaitは非同期的な方法の完成を待つために使われます.
もう一つ面白い文法の規定があります.awaitはasync関数にしか現れません.そして、注意深い友達から質問があります.awaitがasync関数の中にしか現れないなら、このasync関数はどうやって呼びますか?
awaitでasync関数を呼び出す必要があるなら、この呼び出しの外はasync関数をもう一つ包装しなければなりません.そして……死のサイクルに入ります.いつまでたってもいい日はありません.
async関数がawaitで呼び出す必要がないとしたら、asyncはいったいどんな役割を果たしますか?
asyncはどんな役割をしますか?
この問題の鍵はasync関数はどうやってその戻り値を処理しますか?
もちろん、私たちはreturn文を通じて直接に私たちの欲しい値を返してほしいですが、もしそうなら、awaitということはないようです.だから、コードを書いてみて、何を返しますか?
async関数が戻ってきたのはPromiseオブジェクトですので、最外階でawaitでその戻り値を取得できない場合、もちろん元の方式でこのPromiseオブジェクトをthen()チェーンで処理します.このように.
Promiseの特徴を連想します.待ち時間がないので、awaitがない場合はasync関数を実行します.すぐ実行して、Promiseオブジェクトに戻ります.そして、後の文をブロックすることはありません.これは普通にPromiseオブジェクトに戻る関数と同じです.
次のポイントはawaitキーワードにあります.
awaitは一体何を待っていますか?
一般に、awaitはasync関数の完成を待っていると考えられています.しかし、文法的にはawaitが待っているのは表現です.この表現の計算結果はPromiseオブジェクトまたは他の値です.
async関数はPromiseオブジェクトに戻るので、awaitはasync関数の戻り値を待つために使えます.これはawaitがasync関数を待っていると言ってもいいですが、それなどが実際の戻り値です.awaitはPromiseオブジェクトなどに限らず、任意の表現の結果を待つことができますので、awaitの後は実際に普通の関数に接続して呼び出したり、直接量を呼ぶことができます.したがって、以下の例は完全に正しく動作します.
awaitは待ちたいもの、Promiseの対象、または他の値を待っています.まず、awaitは演算子です.表現を構成するために、await表現の演算結果はそれなどのものによって決まります.
もしそれがPromiseオブジェクトでないなら、await表式の演算結果はそれが待っているものです.
もしそれがPromiseオブジェクトであるなら、awaitは忙しいです.後のコードをブロックし、Promiseオブジェクトresoveを待って、resoveの値を得て、await表現の演算結果とします.
上の渋滞という言葉を見て、慌てるでしょう.安心してください.これはawaitがasync関数に使わなければならない理由です.async関数の呼び出しは、ブロックを引き起こすことはありません.その内部のすべてのブロックは、Promiseオブジェクトに非同期的に実装されます.
async/awaitは何をしてくれましたか?
簡単な比較をする
以上では、asyncがその後の関数(関数式またはLambanda)の戻り値をPromiseオブジェクトにパッケージ化すると説明しましたが、awaitはこのPromiseが完了するのを待って、その結果を返します.
例えば、setTimeoutで時間がかかる非同期操作をシミュレートします.まず、async/awaitを使わないとどう書きますか?
もう一つの疑問が発生しました.この二つのコードは、非同期呼出の処理(実際にはPromiseオブジェクトに対する処理)の違いがあまり明らかではないです.async/awaitを使うには、コードを多く書く必要があります.その利点はどこにありますか?
async/awaitの優位はthenチェーンを処理することにあります.
単一のPromiseチェーンはasync/awaitの優位性を発見できませんでした.しかし、複数のPromiseからなるthenチェーンを処理する必要があれば、優位性が現れます.
一つのサービスを複数のステップに分けて完了すると仮定し、各ステップは非同期であり、前のステップの結果に依存する.非同期動作をシミュレーションするためにsetTimeoutを使用したままである.
async/awaitで実現すれば、こうなります.
もっとかっこいいのがあります
今は業務要求を変更します.まだ3つのステップですが、各ステップは前の各ステップの結果が必要です.
asyncとawaitは何をしていますか?
いずれの名前も意味があります.まずは字面の意味から分かります.asyncは「非同期」の略で、awaitはasync waitの略と考えられます.だからasynctionは非同期であるということをよく理解しておくべきです.awaitは非同期的な方法の完成を待つために使われます.
もう一つ面白い文法の規定があります.awaitはasync関数にしか現れません.そして、注意深い友達から質問があります.awaitがasync関数の中にしか現れないなら、このasync関数はどうやって呼びますか?
awaitでasync関数を呼び出す必要があるなら、この呼び出しの外はasync関数をもう一つ包装しなければなりません.そして……死のサイクルに入ります.いつまでたってもいい日はありません.
async関数がawaitで呼び出す必要がないとしたら、asyncはいったいどんな役割を果たしますか?
asyncはどんな役割をしますか?
この問題の鍵はasync関数はどうやってその戻り値を処理しますか?
もちろん、私たちはreturn文を通じて直接に私たちの欲しい値を返してほしいですが、もしそうなら、awaitということはないようです.だから、コードを書いてみて、何を返しますか?
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);
アウトプットを見て、はっと悟りました.アウトプットはPromiseの対象です.c:\var\test> node --harmony_async_await .
Promise { 'hello async' }
したがって、async関数はPromiseオブジェクトを返します.この情報は文書からも入手できます.async関数(関数文、関数式、Lamda式を含む)はPromiseオブジェクトに戻ります.関数の中でreturnの直接量があれば、asyncはこの直接量をPromise.resove()を通じてPromiseオブジェクトにパッケージします.async関数が戻ってきたのはPromiseオブジェクトですので、最外階でawaitでその戻り値を取得できない場合、もちろん元の方式でこのPromiseオブジェクトをthen()チェーンで処理します.このように.
> testAsync().then(v => {
console.log(v); // hello async
});
今から振り返れば、async関数が戻り値を示さなかったら、どうなりますか?簡単に考えられます.Promise.resoveに戻ります.Promiseの特徴を連想します.待ち時間がないので、awaitがない場合はasync関数を実行します.すぐ実行して、Promiseオブジェクトに戻ります.そして、後の文をブロックすることはありません.これは普通にPromiseオブジェクトに戻る関数と同じです.
次のポイントはawaitキーワードにあります.
awaitは一体何を待っていますか?
一般に、awaitはasync関数の完成を待っていると考えられています.しかし、文法的にはawaitが待っているのは表現です.この表現の計算結果はPromiseオブジェクトまたは他の値です.
async関数はPromiseオブジェクトに戻るので、awaitはasync関数の戻り値を待つために使えます.これはawaitがasync関数を待っていると言ってもいいですが、それなどが実際の戻り値です.awaitはPromiseオブジェクトなどに限らず、任意の表現の結果を待つことができますので、awaitの後は実際に普通の関数に接続して呼び出したり、直接量を呼ぶことができます.したがって、以下の例は完全に正しく動作します.
function getSomething() {
return "something";
}
async function testAsync() {
return Promise.resolve("hello async");
}
async function test() {
const v1 = await getSomething();
const v2 = await testAsync();
console.log(v1, v2);
}
test();
awaitは待ちます.それから.awaitは待ちたいもの、Promiseの対象、または他の値を待っています.まず、awaitは演算子です.表現を構成するために、await表現の演算結果はそれなどのものによって決まります.
もしそれがPromiseオブジェクトでないなら、await表式の演算結果はそれが待っているものです.
もしそれがPromiseオブジェクトであるなら、awaitは忙しいです.後のコードをブロックし、Promiseオブジェクトresoveを待って、resoveの値を得て、await表現の演算結果とします.
上の渋滞という言葉を見て、慌てるでしょう.安心してください.これはawaitがasync関数に使わなければならない理由です.async関数の呼び出しは、ブロックを引き起こすことはありません.その内部のすべてのブロックは、Promiseオブジェクトに非同期的に実装されます.
async/awaitは何をしてくれましたか?
簡単な比較をする
以上では、asyncがその後の関数(関数式またはLambanda)の戻り値をPromiseオブジェクトにパッケージ化すると説明しましたが、awaitはこのPromiseが完了するのを待って、その結果を返します.
例えば、setTimeoutで時間がかかる非同期操作をシミュレートします.まず、async/awaitを使わないとどう書きますか?
function takeLongTime() {
return new Promise(resolve => {
setTimeout(() => resolve("long_time_value"), 1000);
});
}
takeLongTime().then(v => {
console.log("got", v);
});
async/awaitに変えたら、こうなります.function takeLongTime() {
return new Promise(resolve => {
setTimeout(() => resolve("long_time_value"), 1000);
});
}
async function test() {
const v = await takeLongTime();
console.log(v);
}
test();
目の先の学友はすでにtake LongTime()がasyncと申明していないことを発見しました.実は、take LongTime()自体は帰ってきたPromiseの対象です.asyncを入れないと結果は同じです.もし分からなかったら、振り返ってみてください.もう一つの疑問が発生しました.この二つのコードは、非同期呼出の処理(実際にはPromiseオブジェクトに対する処理)の違いがあまり明らかではないです.async/awaitを使うには、コードを多く書く必要があります.その利点はどこにありますか?
async/awaitの優位はthenチェーンを処理することにあります.
単一のPromiseチェーンはasync/awaitの優位性を発見できませんでした.しかし、複数のPromiseからなるthenチェーンを処理する必要があれば、優位性が現れます.
一つのサービスを複数のステップに分けて完了すると仮定し、各ステップは非同期であり、前のステップの結果に依存する.非同期動作をシミュレーションするためにsetTimeoutを使用したままである.
/**
* n, ( )
* n + 200,
*/
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
今はPromise方式でこの三つのステップの処理を実現します.function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1507.251ms
出力結果resultはStep 3()のパラメータ700+200=900です.doIt()は3つのステップを順次実行し、合計300+500+700=1500ミリ秒を使用し、consone.time()/soline.timeEnd()と計算した結果と一致した.async/awaitで実現すれば、こうなります.
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
結果は前のPromiseと同じですが、このコードはかなりはっきりしているように見えます.同期コードとほぼ同じです.もっとかっこいいのがあります
今は業務要求を変更します.まだ3つのステップですが、各ステップは前の各ステップの結果が必要です.
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}
今回はまずasync/awaitで書きます.async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 800 = 300 + 500
// step3 with 1800 = 300 + 500 + 1000
// result is 2000
// doIt: 2907.387ms
実行時間が長くなったと感じる以外に、前の例と変わらないようです.焦らないでください.それをPromiseと書いたらどうなりますか?function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => {
return step2(time1, time2)
.then(time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
return step3(time1, time2, time3);
})
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();