1. khsk
Changes in title
-【JavaScript】非同期処理/Promise/asyncと聞くとにビビっちゃう人を救う
+【JavaScript】非同期処理/Promise/asyncと聞くとビビっちゃう人を救う
Changes in body
Source | HTML | Preview
@@ -1,240 +1,240 @@
## 非同期とは何か?
JavaScriptは**非同期**で実行されます。
非同期で動くとはどういうことかコードを実行して体験してみます。
```sample.js
console.log('#1')
setTimeout(() => {
console.log('#2')
}, 500)
console.log('#3')
```
ブラウザのコンソールかNode.jsで実行してみましょう。
Node.jsで実行するときはターミナルでnode ./sample.jsで出来ます。
```
#1
#3
#2
```
プログラムは上から順に実行されます。
同期処理では、一つ前の実行が終わるまで次の実行は待ちます。
非同期処理では、一つ前の実行に時間がかかる場合、実行完了をまたずに次の処理が行われます。
ざっくり言うと、前の反応を待つのが同期、前の反応を待たないのが非同期です。
JavaScriptは非同期で処理が実行されるため、上記のサンプルコードでは「#1 #2 #3」という順番ではなく「#1 #3 #2」という結果になったのです。
## Promiseとは何か?
上記のサンプルコードを上から順番に実行するためにはどうすればいいのでしょうか?
この問題に対する解がPromiseです
Promiseを使うことで非同期言語のJavaScriptを同期的に書くことが出来ます。
「非同期処理で使うもの = Promise」ではなく「非同期処理の言語を同期的に扱いたい時に使うオブジェクト = Promise」です。
Promiseは以下のメリットを得られます。
- コールバック地獄(もはや死後なので詳細は割愛)を回避できる
- 時間のかかるAPIから取得した値を次の処理に渡せる
- 上から順に実行されるので可読性が上がる
### 使い方
最初のサンプルコードを数字順に表示するコードをPromiseで書いてみます。
```.js
console.log('#1')
const sample = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('#2')
resolve()
}, 500)
})
}
sample()
.then(() => {
console.log('#3')
})
.catch(() => {
console.error('error')
})
```
実行すると、順番に実行されます。
```
#1
#2
#3
```
コードが冗長に感じるかもしれませんが、詳しく見ていきます。
-#### Promisオブジェクトの生成
+#### Promiseオブジェクトの生成
-Promiseを使うためには、最初にPromiseコンストラクタをnewして、初期化されたPromsieオブジェクトを生成します。
+Promiseを使うためには、最初にPromiseコンストラクタをnewして、初期化されたPromiseオブジェクトを生成します。
コンストラクタ引数は関数をとり、その関数の中に非同期処理を書きます。
```.js
const sample = () =>
// 返り値にPromiseオブジェクトを生成
return new Promise((resolve, reject) => {
// 非同期で処理したいことを記述
// 成功したらresolve()を呼ぶ
resolve()
// 失敗したらreject()を呼ぶ
reject()
})
}
```
Promiseは3種類の状態を持っています。
状態によって次に実行されるメソッドが変わります。
一度Pendingから状態が変化した後に、別の状態になることはありません。
- Pending 初期状態
- Fulfilled `resolve()`が呼ばれた時
- Rejected `reject()`が呼ばれた時
#### 次の処理に繋げる
Promiseオブジェクトは、`then()`と`catch()`の2つのメソッドを持っています。
-Promsieの状態がFulfilledの時はthen()が実行され、Rejectedの時はcatch()が実行されます。
+Promiseの状態がFulfilledの時はthen()が実行され、Rejectedの時はcatch()が実行されます。
```.js
sample()
.then(() => {
// sample()でresolve()が実行された後の処理
})
.catch(() => {
// sample()でreject()が実行された後の処理
})
```
thenのコールバック関数の第一引数には、Promiseでresolveに渡した値が渡ってきます。
一旦ここまでがPromiseの基本的な説明になります。
## Promiseを繋げて使う
APIを叩いて値を取得する`getParam`という関数を作成します。
Stringを返す架空のAPIを仮定しています。例えば`/sample/foo`を指定するとfooが返ります。
```.js
const getParam = url => {
- return new Promsie((resolve, reject) => {
+ return new Promise((resolve, reject) => {
const request = new XMLHttpRequest()
request.open('GET', url, true)
request.addEventListener('load', (e) => {
if (request.status === 200) {
resolve(request.responseText)
} else {
reject(request.statusText)
}
})
request.send()
})
}
```
Promiseは繋げて書くことが出来ます。
Promiseチェーンと呼ばれたりします。
```.js
getParam('/sample/foo')
.then(res => {
console.log(res)
return getParam('/sample/bar')
})
.then(res => {
console.log(res)
return getParam('/sample/fuga')
})
.catch(err => {
console.log(err)
})
```
とてもきれいに書けますね!
実行結果は以下(想定)です。
```
'foo'
'bar'
'fuga'
```
## 並列処理
Promiseを使っていると複数の非同期処理が成功後に、何かの処理をしたい時が出てきます。
そんな時に使えるのが`Promise.all`です。
非同期で処理したいものを配列に入れて、全てのPromiseオブジェクトが`fulfilled`になった時にthenが呼ばれます。
```.js
-Promsie.all([
+Promise.all([
getParam('/sample/ringo')
getParam('/sample/gorira')
getParam('/sample/rappa')
getParam('/sample/pantu')
]).then(res => {
console.log(res)
})
```
```
['ringo', 'gorira', 'rappa', 'pantu']
```
同様に`Promise.race`は引数に配列を受けて、その中のどれか1つが`fulfilled`または`refected`になった時にthenが呼ばれます。
## async/awaitを使う
-PromsieチェーンによりJavaScriptはすっきりと 同期的なコードを書くこと可能になりました。
+PromiseチェーンによりJavaScriptはすっきりと 同期的なコードを書くこと可能になりました。
async/awaitを使うことでさらに分かりやすいコードを書くことが出来ます。
```.js
const getAsyncData = async id => {
try {
// idを使ってAPI経由でnameを取得
const name = await getParam(`/sample1/${id}`)
// nameを取得した後に、nameを使ってbelongsを取得
const belongs = await getParam(`/sample1/${name}`)
return belongs
} catch(err) {
throw err
}
}
```
async/awaitを使うことで、then()やcatch()という記述をする必要がなく、より直感的に同期的な処理を実現出来ます。
ポイントは以下です。
- awaitは、直後に記述されたPromiseオブジェクト内で処理が完了するまで処理を一時停止します。
-- awaitはPromsieの処理完了時に持っている値を取り出し変数への代入を行います。
+- awaitはPromiseの処理完了時に持っている値を取り出し変数への代入を行います。
- awaitはasyncの中でのみ使えます。
- 例外処理はtry-catchで行います。
## まとめ
-JavaScriptで分かりにくいPromsieについて解説しました。
-JavaScriptはそもそも非同期で処理する言語であり、欠点を補い同期的な処理を行うためにPromsieが使われるということが理解できればPromsieは使いこなせるのではないかと思います。
+JavaScriptで分かりにくいPromiseについて解説しました。
+JavaScriptはそもそも非同期で処理する言語であり、欠点を補い同期的な処理を行うためにPromiseが使われるということが理解できればPromiseは使いこなせるのではないかと思います。
async/await、PromiseはIE11以外のモダンブラウザでは全て対応しているので、プロジェクトでもどんどん使っていきましょう!