私の理解:
async の役割は、この関数が非同期であることを定義することです。async は関数の前に配置されるキーワードであり、関数内で 1 を返し、"1" を返し、新しい Promise() を返します。
外部印刷の関数は promise オブジェクトとして取得され、return の値は関数 .then を通じて取得されます。
await の機能は待機することです 。それが待機している promise オブジェクトでない場合、次のコードをブロックしません。それ以外の場合、promise オブジェクトを待機している場合は次のコードをブロックし、直接データが await で装飾されている場合は解決されます。これは await の仕事です
1. async と await の機能
- asyncは「非同期」の略で、 await は待機することを意味します。
- async は関数が非同期であることを宣言するために使用され、await は操作が完了するのを待ちます。
-
async/await は、非同期コードを記述する新しい方法です。非同期コードの以前のソリューションは、コールバックと promise でした。
-
async/await は、promise と同様にノンブロッキングです。
-
async/await は、非同期コードの外観と動作を同期コードのようにします。その力はここにある。
2.非同期は何をしますか?
この質問の鍵は、非同期関数がその戻り値をどのように処理するかです!
もちろん、return ステートメントを介して直接必要な値を返すことができることを願っていますが、そうであれば、何も待つ必要はないようです。それで、いくつかのコードを書いてみて、それが何を返すか見てみましょう:
<script>
async function test(){
return 'hello async';
}
let result = test();
console.log(result);
</script>
出力を見たとき、突然気がつきました — 出力は Promise オブジェクトです。
Promise {<resolved>: "hello async"}
したがって、非同期関数が返すのは Promise オブジェクトです。The async function (include function statement, function expression, and Lambda expression) will return a Promise object. 関数で直接値が返される場合、非同期は Promise.resolve() を介して直接値を Promise オブジェクトにカプセル化します。
async 関数は Promise オブジェクトを返すので、最外層が await を使用して戻り値を取得できない場合は、もちろん元の方法を使用する必要があります: then() チェーンを使用して、この Promise オブジェクトを次のように処理します。
async function test(){
return 'hello async';
}
test().then((val) => {
console.log(val); //hello async
})
今思い返してみると、非同期関数が値を返さなかったらどうなるでしょうか? Promise.resolve(undefined) を返すことは容易に想像できます。
Promise の特徴について考えてみてください。待機がないため、await なしで async 関数を実行すると、すぐに実行されて Promise オブジェクトが返され、次のステートメントがブロックされることはありません。これは、Promise オブジェクトを返す通常の関数と同じです。
次に重要なポイントは await キーワードです。
3.待っているのは何ですか?
async 関数は Promise オブジェクトを返すため、await を使用して async 関数の戻り値を待つことができます。await は async 関数を待っているとも言えますが、実際には async 関数を待っていることは明らかです。戻り値。await は Promise オブジェクトを待機するために使用されるだけでなく、任意の式の結果を待機できることに注意してください。したがって、await の後に、通常の関数呼び出しまたは直接数量を実際に続けることができます。したがって、次の例は完全に正常に機能します。
function getSomething(){
return "something";
}
async function testAsync(){
return Promise.resolve('hello async');
}
async function test(){
let v1 = await getSomething();
let v2 = await testAsync();
console.log(v1,v2);
}
test();
console.log('我执行了');
//执行结果为:
//我执行了
//something,hello async
await 何を待つかを待ち、次に
await は、待機しているもの、Promise オブジェクト、またはその他の値を待機します。まず、await は式を構成するために使用される演算子であり、await 式の結果は何を待っているかによって決まるということから始めなければなりません。
Promise でない場合、await 式は何を待っているかを評価します。
Promise オブジェクトを待つと、await がビジー状態になるため、次のコードをブロックし、Promise オブジェクトが解決するのを待って、解決された値を await 式の演算結果として取得します。
上記のブロッキングという言葉を見て、私はパニックになりました...心配しないでください。これが、非同期関数で await を使用する必要がある理由です。async 関数呼び出しはブロッキングを発生させず (つまり、13 行目のコードはブロックされません)、すべての内部ブロッキングは非同期実行のために Promise オブジェクトにカプセル化されます。
async/await は私たちのために何をしますか
簡単な比較をする
async は、後続の関数 (関数式または Lambda) の戻り値を Promise オブジェクトにカプセル化し、await は Promise が完了するのを待って解決の結果を返すことを上で説明しました。
たとえば、setTimeout を使用して、時間のかかる非同期操作をシミュレートします. まず、async/await を使用せずに記述する方法を見てみましょう。
function takeLongTime(){
return new Promise((resolve) => {
setTimeout(() => resolve('long time value'),1000);
})
}
takeLongTime().then((v) => {
console.log('get:',v);
})
代わりに async/await を使用すると、このようになります。
function takeLongTime(){
return new Promise((resolve) => {
setTimeout(() => resolve('long time value'),1000);
})
}
async function test(){
let v = await takeLongTime();//等待异步操作的结果,阻塞后面代码的执行
console.log(v);
}
鋭い学生は、 takeLongTime() が async として宣言されていないことを発見しました。実は takeLongTime() 自体が返された Promise オブジェクトであり、async の有無にかかわらず結果は同じです. わからない場合は、上記の「async は何をするのか」に戻って見てください.
別の疑問が生じます. これら 2 つのコードでは、非同期呼び出し (実際には Promise オブジェクトの処理) を処理する 2 つの方法の違いは明らかではなく、async/await を使用する場合でもより多くのコードが必要になります。
async/await の利点は、then チェーンを処理できることです。
単一の Promise チェーンでは async/await の利点を見つけることはできませんが、複数の Promise で構成される then チェーンを処理する必要がある場合は、その利点を反映できます (興味深いことに、Promise は then チェーンを介して多層コールバックの問題を解決します。 async/await を使用してさらに最適化します)。
ビジネスが複数のステップで完了するとします。各ステップは非同期であり、前のステップの結果に依存します。非同期操作をシミュレートするために、引き続き 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 メソッドを使用して、これら 3 つのステップの処理を実現します。
function doIt(){
console.time('doIt');
let time1 = 300;
step1(time1)
.then((time2) => step2(time2))
.then((time3) => step3(time3))
.then((result) => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
})
}
doIt();
//执行结果为:
//step1 with 300
//step2 with 500
//step3 with 700
//result is 900
//doIt: 1510.2490234375ms
出力結果は step3() のパラメータ 700 + 200 = 900 です。doIt() は 3 つのステップを順番に実行し、合計で 300 + 500 + 700 = 1500 ミリ秒かかります。これは、console.time()/console.timeEnd() によって計算された結果と一致しています。
async/awaitで実装するとこうなります。
async function doIt() {
console.time('doIt');
let time1 = 300;
let time2 = await step1(time1);//将Promise对象resolve(n+200)的值赋给time2
let time3 = await step1(time2);
let result = await step1(time3);
console.log(`result is ${result}`);
console.timeEnd('doIt');
}
doIt();
//执行结果为:
//step1 with 300
//step2 with 500
//step3 with 700
//result is 900
//doIt: 1512.904296875ms
結果は以前の Promise 実装と同じですが、このコードは同期コードとほぼ同じで、よりきれいに見えます。
さらにクーラーがあります
ビジネス要件を変更するには、まだ 3 つのステップがありますが、各ステップには前の各ステップの結果が必要です。
/*
* 传入参数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(m,n){
console.log(`step2 with ${m} + ${n}`);
return takeLongTime(m + n);
}
function step3(k,m,n){
console.log(`step3 with ${k} + ${m} + ${n}`);
return takeLongTime(k + m + n);
}
今回は、async/await を使用して次のように記述します。
async function doIt() {
console.time('doIt');
let time1 = 300;
let time2 = await step1(time1);//将Promise对象resolve(n+200)的值赋给time2
let time3 = await step2(time2,time1);
let result = await step3(time3,time2,time1);
console.log(`result is ${result}`);
console.timeEnd('doIt');
}
doIt();
//执行结果为:
//step1 with 300
//step2 with 500 + 300
//step3 with 1000 + 500 + 300
//result is 2000
//doIt: 2916.655029296875ms
実行時間が長くなった以外は、前の例と同じようです! 心配しないで、Promise として実装されたらどうなるかよく考えてみてください。
function doIt() {
console.time('doIt');
let time1 = 300;
step1(time1)
.then((time2) => {
return step2(time1,time2)
.then((time3) => [time1,time2,time3])//step3需要用到time1,time2,time3,因此需要返回
})
.then((times) => {
let [time1,time2,time3] = times;
return step3(time1,time2,time3)
})
.then((result) => {
console.log(`result is ${result}`);
console.timeEnd('doIt');
})
}
doIt();
//执行结果为:
//step1 with 300
//step2 with 300 + 500
//step3 with 300 + 500 + 1000
//result is 2000
//doIt: 2919.49609375ms
少し複雑な感じですか?この一連のパラメーター処理は、Promise ソリューションのアキレス腱です。パラメーターの受け渡しが面倒すぎて、見ているだけで目まいがします!
注意点
とりあえず、async/awaitは理解できましたか?しかし実際には、言及されていないことがいくつかあります - Promise は拒否するかもしれません。
await コマンドの背後にある Promise オブジェクトは拒否される可能性があるため、await コマンドを try...catch コード ブロックに配置することをお勧めします。
async function myFunction() {
try {
await somethingThatReturnAPromise();
} catch (err){
console.log(err);
}
}
//另一种写法
async function myFunction() {
await somethingThatReturnAPromise().catch(function(err) {
console.log(err);
})
}