blog

JS非同期02:プロミス、async-await

toc]pending->resolved->またはpending->rejectedの3つのpromiseの状態は、不可逆的な状態への変化です。...

Jun 11, 2020 · 5 min. read
シェア

toc

Promise

3つの状態

  • 保留→解決済み→または保留→却下

  • この変化は不可逆的です

const p1 = new Promise((resolve, reject) => {
})
console.log("p1", p1)
const p2 = new Promise((resolve, reject) => {
 setTimeout(() => {
 resolve();
 })
})
console.log("p2", p2)
setTimeout(() => console.log("p2-setTimeout", p2))
const p3 = new Promise((resolve, reject) => {
 setTimeout(() => {
 reject();
 })
})
console.log("p3", p3)
setTimeout(() => console.log("p3-setTimeout", p3))

州のパフォーマンス

  • 保留状態は、then and catchのトリガーにはなりません。
  • トリガーを解決し、キャッチ。
  • rejectはcatchをトリガーします。

その後とキャッチの状態変化

  • を返し、正常であれば解決済み、エラーがあれば拒否されます。
  • キャッチが正常であればresolvedを返しますが、エラーがあればrejectを返します。
const p1 = Promise.resolve().then(() => {
 return 100;
});
console.log("p1", p1);
p1.then(() => {
 console.log("p1 then");
});
const p2 = Promise.resolve().then(() => {
 throw new Error("then error");
});
console.log("p2", p2);
p2.then(() => {
 console.log("p2 then");
}).catch((err) => {
 console.log("p2 catch error", err);
});
const p3 = Promise.reject("p3 error").catch(err => {
 console.error(err);
});
console.log("p3", p3); // resolved thenコールバックをトリガーする
p3.then(() => {
 console.log("p3 then");
});
const p4 = Promise.reject("p3 error").catch(err => {
 throw new Error("p4 catch error");
});
console.log("p4", p4); // rejected catchコールバックをトリガーする
p4.then(() => {
 console.log("p4 then"); // 印刷しない
}).catch((err) => {
 console.log("p4 catch", err);
});

プロミストピック

Promise.resolve().then(() => {
 console.log(1);
}).catch(() => {
 console.log(2);
}).then(() => {
 console.log(3);
})
12
Promise.resolve().then(() => {	// エラーは拒否された
 console.log(1);
 throw new Error("error1");
}).catch(() => {	// エラーが報告されなければresolvedを返す
 console.log(2);
}).then(() => {
 console.log(3);
})
123
Promise.resolve().then(() => {
 console.log(1);
 throw new Error("error1");
}).catch(() => {
 console.log(2);
}).catch(() => {
 console.log(3);
})
12

async-await

非同期開発

  1. 非同期コールバック コールバックと地獄

質問:コールバック地獄

  1. Promiseは、連鎖した呼び出しをキャッチするだけでなく、コールバック関数にも基づきます。

  2. async-awaitは、コールバック関数を完全に排除した同期構文です。

async-awaitの基本的な使い方

  1. await続いてPromise関数
  2. 非同期関数が続きます。

async-awaitPromise との関係

  • async-awaitは、非同期コールバックを排除する究極の手段です。

  • しかし、プロミスは互いに排他的なものではなく、補完的なものです。

  • 非同期関数は Promise オブジェクトを返す必要があります。

  • try-catch は .catch の代わりに例外をキャッチします。

非同期実行は Promise オブジェクトを返さなければなりません。

async function fn1() {
 // return "fn1" // returnPromiseに相当する.resolve("fn1")
 return Promise.resolve(200);
}
const res1 = fn1();
console.log(res1);
res1.then(data => {
 console.log("res1 data", data);
});

await は then() と同じです。

(async function () {
 const p1 = Promise.resolve(300);
 const data = await p1;
 console.log("data", data);
})();
(async function () {
 const p1 = await 400; // await Promiseに相当する。.resolve(400)
 const data = await p1;
 console.log("data", data);
})();
(async function () {
 const p1 = await fn1();	
 const data = await p1;
 console.log("data", data);
})();

トライキャッチ

(async function () {
 const p4 = Promise.reject("err");
 try{
 const res = await p4;
 console.log(res);
 }catch (err) {
 console.log("err1", err)
 }
})();
(async function () {
 const p5 = Promise.reject("err");
 const res = await p4; // この時点では拒否状態であり、実行されない。-catch 
 console.log(res)
})();

非同期の本質は、やはりコールバック関数です。

  • jsはシングルスレッド、非同期はイベントループに基づきます。
  • 非同期awaitは単なる構文糖です。
async function async1() {
 console.log("async1 start");
 await async2();
 // await 次の行は非同期になる。
 console.log("async1 end");
}
async function async2() {
 console.log("async2");
}
console.log("script start");
async1();
console.log("script end");

プリンタブル

script start
async1 start
async2
script end
async1 end

最初に同期コードを実行

イベントループの開始

非同期コードの実行

非同期関数の追加

async function async1() {
 console.log("async1 start");
 await async2();
 console.log("async1 end");
 await async3();
 console.log("async1 end 2");
}
async function async2() {
 console.log("async2");
}
async function async3() {
 console.log("async3");
}
console.log("script start");
async1();
console.log("script end");

プリンタブル

script start
async1 start
async2
script end
async1 end
async3
async1 end 2

アプリケーションシナリオ

  • for-in は通常の同期トラバーサルです。
  • for-of は非同期走査によく使われます。

通常の非同期トラバーサル・コードは次のとおりです。

function muti(num) {
 return new Promise(resolve => {
 setTimeout(() => {
 resolve(num * num);
 }, 1000);
 });
}
const nums = [1, 2, 3];
nums.forEach(async (i) => {
 const res = await muti(i);
 console.log(res);
});

1秒後、すべて同時にプリントアウト

1枚ずつ印刷する必要がある場合は、for-ofメソッドを使用する必要があります。

awaitを実行するには、非同期関数でラップする必要があることに注意してください。

function muti(num) {
 return new Promise(resolve => {
 setTimeout(() => {
 resolve(num * num);
 }, 1000);
 });
}
const nums = [1, 2, 3];
!(async function () {
 for (let i of nums) {
 const res = await muti(i);
 console.log(res);
 }
})();
Read next

これはサウンド付きのデモである

私は時々世界最大の同性出会い系コミュニティをぶらぶらして、私は偶然Tone.jsと呼ばれるオープンソースのライブラリを発見し、私の若い心に種を植えました。それで何かできそうな気がして、viteとvue3を体験するために、ついに手を出しました。練習と学習のために常にデモを書く必要があり、空き時間を費やして、音でデモをジャックしました...

Jun 11, 2020 · 2 min read