Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JS 入門 async/await について

C302e84057a922dce0ecbe80207e3fcc?s=47 mu_zaru
November 05, 2020

JS 入門 async/await について

配信動画はこちら
https://www.youtube.com/watch?v=HFBZvK9_OUc&feature=youtu.be

もし良かったらムーザルちゃんねるのチャンネル登録お願いします!
https://www.youtube.com/channel/UCLPHXwLp90A5R69Eltxo-sg

Twitter でもプログラミングネタをつぶやいているのでフォローお待ちしております。
ムー
https://twitter.com/mu_book
zaru
https://twitter.com/zaru

C302e84057a922dce0ecbe80207e3fcc?s=128

mu_zaru

November 05, 2020
Tweet

Transcript

  1. YouTube Live (2020.11.04 Thur. 21:00~)

  2. 話す人 現役のエンジニア二人 赤貝が好きな CTO と デザイン勉強中のエンジニア @mu_vpoe 最近の仕事は figma で画

    面設計をつくることで す。英語の勉強してる。 ムー zaru @zaru CTO, Love 赤貝, JavaScript, Firebase, Web Components. Twitter フォロー お願いします!
  3. 非同期処理は簡単 async, await を使えば 本当か なぁ? 嘘でしょ …かも?

  4. await で非同期の完了を待つ const res = await fetch('http://localhost:3000/'); JavaScript 非同期処理 完了を待つよ、という指示

    非同期な処理の前に await と置くことで、同期的にコードを書く ことができて便利! という、とても簡単で便利な感じですね!! ???
  5. 非同期 って何?

  6. 同期と非同期処理の違い syncFuncA() syncFuncB() syncFuncC() 同期処理の流れ asyncFuncA() syncFuncB() syncFuncC() 非同期処理の流れ //

    A が終わってから B // B が終わってから C // A を待たずに B // B が終わってから C 裏で処理をして いるイメージ 面倒くさ いジャン 非同期 嫌だ // A がいつ終わるかは // 分からない プログラマ的には、書いたコード順に実行して行って欲 しい(同期的)。非同期な処理が入ると、結果を受け 取って次の処理をするためのコードを書くのが面倒。
  7. 非同期 必要ない んじゃ?

  8. ブラウザはとにかく忙しい マウス移動 ボタンクリック 文字選択 フォーム入力 HTML レンダリ ング CSS スタ

    イル描画 ユーザ操 作へ反応 ブラウザは HTML の表示に加えて、ユーザ操作に対する反応をし なくてはならず、絶え間なく忙しい。忙しいけど頑張っている。 サーバとの 通信
  9. 時間のかかる処理があると固まる めちゃく ちゃ重い 処理 時間のかかる処理があると、ブラウザは他の作業ができな くなる。ユーザの操作も受け付けることができない。ブラ ウザも頑張っているが、仕方がない…。 ・・・ ブラウザが固まって ユーザが操作不能に

    ❌ (*) なぜ他の処理ができないのかというとシングルスレッドだからという ことなのだけど、突っ込んだ話になるので別の機会に…
  10. 固まるデモ https://gist.github.com/zaru/b8275a59305eff78560f8a90b51c1e4b

  11. 時間のかかる処理があっても待たない めちゃく ちゃ重い 処理 あとで そのすきに色んな 操作を受け付ける ことができる ざっくり言うと、時間のかかる処理が終わるのを待たず に、他の処理を受け付けられるようにする

    => 非同期処理 非同期 必要だ
  12. 非同期処理の結果を受け取る

  13. 通信処理() もし同期処理だったら リクエスト レスポンス この間、他の 操作や処理は 何もできない サーバ ❌ 通信処理()

    通信は非同期 リクエスト レスポンス 通信中、他の 操作を受け付 ける サーバ おさらい
  14. 通信処理() もし同期処理だったら リクエスト レスポンス この間、他の 操作や処理は 何もできない サーバ ❌ 通信処理()

    通信は非同期 リクエスト レスポンス 通信中、他の 操作を受け付 ける サーバ つまり非 同期にし たいんだ ね
  15. 通信処理() 通信中、他の 操作を受け付 ける 通信は非同期 リクエスト レスポンス サーバ const res

    = 同期_通信処理('http://localhost:3000/'); // res 変数には通信処理の結果が入って来るので、すぐ使える JavaScript 通信処理() もし同期処理だったら リクエスト レスポンス この間、他の 操作や処理は 何もできない サーバ ❌ シンプルだ けど操作で きないのは 困る
  16. 通信処理() もし同期処理だったら リクエスト レスポンス この間、他の 操作や処理は 何もできない サーバ ❌ 通信処理()

    通信中、他の 操作を受け付 ける 通信は非同期 リクエスト レスポンス サーバ const res = 非同期_通信処理('http://localhost:3000/'); // res 変数には通信処理の結果は入ってこない!! JavaScript 困る 結果が使えないと意味ない…!
  17. - コールバック関数 - Promise ~ then - Promise ~ await

    結果を受け取る3つの方法 Promise ...?
  18. コールバック関数で受け取る 昔から使われている XMLHttpRequest で結果を受け取るには load のイベ ントリスナーに関数を登録しておく。非同期処理の結果を受け取るには、こ のようなイベントやコールバック関数でやるのが昔の JS 流儀。

    問題は、非同期処理の書き方が統一されていないことと、連続した非同期処 理をすると深いネスト構造になり破綻しやすいこと。 const xhr = new XMLHttpRequest(); xhr.addEventListener('load', (response) => { console.log(response.target.responseText); }); xhr.open('GET', 'http://localhost:3000/'); xhr.send(); XMLHttpRequest コールバック関数
  19. 波動拳 a.k.a Callback Hell fs.readdir(source, function (err, files) { if

    (err) { console.log('Error finding files: ' + err) } else { files.forEach(function (filename, fileIndex) { console.log(filename) gm(source + filename).size(function (err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function (width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } }) http://callbackhell.com/
  20. コールバック関数 function callback(data) { console.log(data); } function something(id, callback) {

    const result = `ID: ${id}`; callback(result) } something('zaru', callback); JS 初学者向け 通称、コールバック関数 特別な機能があるわけで はなく単なる関数定義 引数に関数自体を渡すことができる ここでは関数は実行されない点に注意 引数の関数に、処理した結果を渡し た上で実行する こうすることで特定の処理結果を任 意の関数に任せることができて便利 1 2 3
  21. Promise の登場 ES2015 からの新機能

  22. Promise が解決すること - 非同期処理の標準化(どんな処理も同じ書き方に統一される) - 連続した非同期処理を簡単にかける - 非同期処理に関するいろいろな操作方法の提供 つまり 良い感じ

    のやつ
  23. Promise は3つの状態を持つ Pending Fulfilled Rejected 最初は Pending (待機) で、非同期処理が正常に終わったら Fulfilled

    (満足) へ、なんらかの理由で失敗した場合は Rejected (拒否) 状態に移る。 const promise = asyncFunc(); // Promise{<pending>} promise.then((response) => { // Promise{<fulfilled>} }).catch((error) => { // Promise{<rejected>} }); Promise の基本構文 正常に終わる場合は then へ 失敗した場合は catch へ
  24. Promise は then で受け取る fetch は XMLHttpRequest と同じように通信ができる。違う点は Promise というオブジェクトを使って非同期処理をする所。

    Promise はコールバック関数とは違い、標準化され使い方が統一されてい る。then でつないでいくことで、連続した非同期処理をネストさせずに1直 線で書くことができるのがメリット。 fetch('http://localhost:3000/') .then((response) => { return response.text(); }) .then((response) => { return response; }); fetch then の中で受け取れる 次の非同期処理もつなげられる
  25. await の登場 ES2017 からの新機能

  26. await はその場で待つ await を使うと then を使わずに、その場で待ってくれる。つまり、コード の書き方としては同期的に書けるが、実際の処理は非同期で行うので、他の 処理を止めることはない、いいとこ取りな機能。 const response

    = await fetch('http://localhost:3000/'); const text = await response.text(); console.log(text); fetch スッキリ
  27. await 拒否の受け取り方 const response = await fetch('http://localhost/').catch((error) => { console.log(error);

    }); try { const response = await fetch('http://localhost/') } catch (error) { console.log(error); } ドットチェイン catch で 受け取ることができる try の catch でも受け取れる どちらで書いた方がいいかはケースバイケースだが、ドッ トチェインの catch で受け取った方がシンプルな書き方 になることが多い。
  28. await 便利〜 つまり Promise な非同期処理の結果 を受け取るだけなら await 付けておけ ば OK

  29. asyncは?

  30. asyncの使い方 ES2017 からの新機能

  31. async は非同期関数を作る async function asyncFunc() { return 1; } function

    asyncPromise(){ return new Promise((resolve) => resolve(1)) } asyncPromise().then((res) => res ); asyncFunc().then((res) => res ); Promise と async 関数の前に置くことで自動で Promise を返す非同期関数になる 手動で Promise オブジェクトを 作って返す関数と基本的には同じ 呼び出し方も then や await など で同じように使える 非同期処理を使うだけなら async は Promise を手動で作るのと 同じなんだ〜くらいの認識で OK
  32. await は async 内じゃないと使えない ❌ 実はこれはエラーになる const response = await

    fetch('http://localhost/'); ✅ async 関数の中じゃないと await は使えない async function fetchUrl() { const response = await fetch('http://localhost/'); } (async () => { const response = await fetch('http://localhost/'); })(); async 2020.11 現在では await はトップレベルでは使えず async で非同期宣言を した関数の中でしか使えない。将来的には使えるようになる予定(NodeJS は v14.8 以降使える) https://github.com/tc39/proposal-top-level-await
  33. 簡単だね 本当か?

  34. JS の実行フローについて おまけ

  35. イベントループ タスク タスク タスク タスク タスク ユーザの操作やスクリプトの 実行などタスクを積んでいく 暇になったら古いタスクから 拾って順次処理をしていく

    JavaScript の処理は、イベントループと言われる構造で実行し ている。処理したいタスクをキューに積んでいき、順次処理をし ていくイメージ。
  36. どの順序で出力される? console.log('start'); setTimeout(() => console.log('setTimeout'), 0); (async () => {

    await 0; console.log('async') })(); function promiseFunc() { return new Promise((resolve) => resolve()) } promiseFunc().then(() => console.log('promise')); Promise.resolve().then(() => console.log('resolve')); console.log('end'); JavaScript
  37. どの順序で出力される? console.log('start'); setTimeout(() => console.log('setTimeout'), 0); (async () => {

    await 0; console.log('async') })(); function promiseFunc() { return new Promise((resolve) => resolve()) } promiseFunc().then(() => console.log('promise')); Promise.resolve().then(() => console.log('resolve')); console.log('end'); JavaScript start end async promise resolve setTimeout 答え
  38. タスク タスク タスク タスク タスク タスク タスク タスク macrotask microtask

    レンダリング requestAnimationFrame 描画系の処理 Promise setTimeout I/O Network Mouse Keyboard 1 macrotask から1個タ スクを受け取り処理をす る 3まで完了したら次のタ スクを受け取り処理をす る 2 microtask から全て のタスクを受け取り処 理をする 3 必要があれば描画に関連する処理を行う 無限ループ
  39. ありがとうございました! 次回は... 未定! 質問感想など呟いていただけると嬉しいです! - ハッシュタグ #mu_zaru - ツイッター情報 @mu_vpoe

    , @zaru チャンネル登録 Good ボタン お願いします! ムーザルちゃんねる