【JS】setTimeoutを用いた、非同期処理入門

## 概要

setTimeoutを用いて、非同期処理の処理順をまとめました。
コールバック -> Promise -> async/await の順に説明する。

## setTimeout

基本構文

```js
setTimeout('コールバック関数', 'タイムアウト時間')
```

1秒後に`hoge`を出力する。

```js

function callback(){
    console.log('hoge')
}

setTimeout(callback, 1000)
```

```none:出力結果
hoge
```

[![alt](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAoAKqj2CdDJyqjBhBci39yld_HqN-lZnYL0Jd9YJavIOdBsoscBdatTyBXfqjE9UnutRWF9vESLv-UawkNafskeP-IdfwfhMdEbvgLmEG09eDa0)](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAoAKqj2CdDJyqjBhBci39yld_HqN-lZnYL0Jd9YJavIOdBsoscBdatTyBXfqjE9UnutRWF9vESLv-UawkNafskeP-IdfwfhMdEbvgLmEG09eDa0)

無名関数を用いて書く。

```js
setTimeout(function(){ console.log('hoge') }, 1000)
```

アロー演算子を用いて書く。

```js

setTimeout(() => { console.log('hoge') }, 1000)
```

アロー演算子を用いて書く。(中括弧を省略)

```js
setTimeout(() => console.log('hoge'), 1000)
```

## 処理順

非同期処理の処理順を確認する。

```js
console.log(1)
setTimeout(() => console.log(2), 1000)
console.log(3)
```

```none:出力結果
1
3
2
```

[![alt](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAoIy_EAytDIzNBoqpKCDQrH1On10iMf9I6PkQdvfIL0Zk7pvPEUxcjztBW4JQaHK6bgNWgN0v006Wy0)](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAoIy_EAytDIzNBoqpKCDQrH1On10iMf9I6PkQdvfIL0Zk7pvPEUxcjztBW4JQaHK6bgNWgN0v006Wy0)

timeout時間 `0秒` でも、処理順は変わらない。

```js
console.log(1)
setTimeout(() => console.log(2), 0)
console.log(3)
```

```none:出力結果
1
3
2
```

[![alt](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAoIy_EAytDIzNBoqpKCDQrH1On10iMf9I6PkQdvfIL0Zi7pvPEUxcjztBW4JQaHK6bgNWgN0v006Wy0)](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAoIy_EAytDIzNBoqpKCDQrH1On10iMf9I6PkQdvfIL0Zi7pvPEUxcjztBW4JQaHK6bgNWgN0v006Wy0)

## コールバック地獄

非同期処理が複数重なると、コールバック地獄に陥る。

```js
setTimeout(() => {
    console.log(1)
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        }, 1000)
    }, 1000)
}, 1000)
```

```none:出力結果
1
2
3
```

[![alt](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pk8fI2r8JIxWKWC2gEBKa93CtDR-qn1eYOFXy-QId-reVDow12YJdvnNdvwJgvUIdMqErAfHdPEQaSgNcfN0v00cWoG00)](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pk8fI2r8JIxWKWC2gEBKa93CtDR-qn1eYOFXy-QId-reVDow12YJdvnNdvwJgvUIdMqErAfHdPEQaSgNcfN0v00cWoG00)

##  コールバック地獄の回避方法

Promise化すると、thenを用いたメソッドチェーンで処理を繋げられる。

```js
new Promise(function(resolve) {
    resolve('Hello')
}).then(function(value) {
    console.log(value)    // Hello
    return 'World'
}).then(function(value) {
    console.log(value)    // World
})
```

```none:出力結果
Hello
World
```

resolve、returnの値が、コールバック関数の引数になる。
アロー演算子を用いて書き換えてみる。

```js
new Promise(resolve => resolve('Hello'))
.then(value => {
    console.log(value)    // Hello
    return 'World'
}).then(value => {
    console.log(value)    // World
})
```

```none:出力結果
Hello
World
```

コールバック地獄を、Promiseで書き直してみる。

```js
function sleep(ms) {
    return new Promise(function(resolve) { 
        setTimeout(function() { 
            resolve() 
        }, ms)
    })
} 

sleep(1000)
.then(function() {
    console.log(1)
    return sleep(1000)
}).then(function() {
    console.log(2)
    return sleep(1000)
}).then(function() {
    console.log(3)
})
```

```none:出力結果
1
2
3
```

Promiseとアロー演算子を用いて書き換えてみる。

```js
const sleep = ms => new Promise(resolve => setTimeout(() => resolve(), ms))

sleep(1000)
.then(() => {
    console.log(1)
    return sleep(1000)
}).then(() => {
    console.log(2)
    return sleep(1000)
}).then(() => {
    console.log(3)
})
```

```none:出力結果
1
2
3
```

[![alt](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pk8fI2r8JIxWKWC2gE2SrjK33qC30GDCQ8cBuVFcaf_jQ7pSkWGeKfHRdvvIbQi0Kb6Iava6PoVbvGBbKlPpyT6keiGhb6PavgLofUIbS3a02Q2i0)](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pk8fI2r8JIxWKWC2gE2SrjK33qC30GDCQ8cBuVFcaf_jQ7pSkWGeKfHRdvvIbQi0Kb6Iava6PoVbvGBbKlPpyT6keiGhb6PavgLofUIbS3a02Q2i0)

async関数内で、Promise関数にawaitを用いると、同期的に処理できる。

```js
function sleep(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms)
    })
}

async function asyncFunc() {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()
```

```none:出力結果
1
2
3
```

async/await とアロー演算子を用いた場合

```js
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

const asyncFunc = async () => {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()
```

```none:出力結果
1
2
3
```

更に、即時関数を用いて書くと、簡潔に書ける。

```js
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

!(async () => {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
})()
```

```none:出力結果
1
2
3
```

[![alt](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAmIYolpabzEM_HiwWPhhgBKWjJ44Yu58B1AB4_CBB66i8jpKbCBD0mD30mqeIA6pvTFUhglzN7Z4gX0KMfnVavPAfINd9y7vARgvUIdmqnLAC_8p4dbIirBuN804a0d0000)](http://www.plantuml.com/plantuml/svg/SoWkIImgAStDuG8pkAmIYolpabzEM_HiwWPhhgBKWjJ44Yu58B1AB4_CBB66i8jpKbCBD0mD30mqeIA6pvTFUhglzN7Z4gX0KMfnVavPAfINd9y7vARgvUIdmqnLAC_8p4dbIirBuN804a0d0000)

## まとめ

非同期処理の処理順をまとめました。
async/await を用いることで、とても簡潔に書けます。
間違い・指摘等があればコメントお願いします。

## 参考文献
- [JavaScriptで即時関数を使う理由](https://qiita.com/katsukii/items/cfe9fd968ba0db603b1e)
- [javascript 即時関数のトラップ](https://chaika.hatenablog.com/entry/2014/10/05/134757)