JavaScriptの基礎2

# モジュール

## 名前付きexport
```javascript:namedExportModule.js
const sampleVariable = "sampleVariable"

const sampleFunc = () => console.log('Hello World!');

// 別ファイルにimportできるようになる
export {sampleVariable, sampleFunc}
```

## 名前付きimport
```javascript:namedImportModule.js
import {sampleVariable, sampleFunc} from "./namedExportModule.js";

// 呼び出し
console.log(sampleVariable) // sampleVariable
console.log(sampleFunc) // sampleFunc() {}
console.log(sampleFunc()) // Hello World!
```

## 名前付きimportのエイリアス
```javascript:namedImportModule.js
import {
    sampleVariable as myVariable,
    sampleFunc as myFunc,
} from "./namedExportModule.js";

// 呼び出し
console.log(myVariable); // sampleVariable
console.log(myFunc); // sumpleFunc() {}
console.log(myFunc()); // Hello World!
```

## 名前付きimportをまとめて行う
```javascript:namedImportModule.js
//  名前付きエクスポートをmyModuleオブジェクトとしてまとめてインポート
import * as myModule from "./namedExportModule.js";

// 呼び出し
console.log(myModule.sampleVariable); // sampleVariable
console.log(myModule.sampleFunc); // sumpleFunc() {}
console.log(myModule.sampleFunc()); // Hello World!
```

## デフォルトexport
デフォルトでクスポートは、モジュールごとに1つだけエクスポートできる特殊なエクスポート
```javascript:defalutExportModule.js
//defaultエクスポートは、モジュールと後に1つだけエクスポートできる
export default function() {
    console.log("Hello World!");
}
```

## デフォルトimport
名前付きインポートの場合、importの後に{}が必要ですが、デフォルトインポートの場合、{}は不要です
```javascript:defaultImportModule.js
// デフォルトエクスポートされたモジュールインポートする場合、{}はつけない
// Appは任意の名前
import App from './defaultExportModule.js'

console.log(App) // App() {}
console.log(App()) // Hello World!
```

## HTMLファイルからモジュールを呼び出す
HTMLファイルからモジュールを利用しているJavaScriptファイルを呼び出す場合、type属性にmoduleを指定
```html:index.html
<script type="module" src="./modules/importModule.js"></script>
```

# 非同期処理
プログラムは通常**同期処理**であり、コードを上から順番に処理していき、1つの処理が終わるまで次の処理は行われない。一方で非同期処理は、ある処理が終わるのを待たずに次の処理を実行していくため、同時に複数の処理を行う。
コールバック関数も何かしらの関数の処理が完了してから引数で渡された関数を処理する非同期処理

## setTimeout()
setTimeout()は指定された時間が経過したところで1度だけ処理を実行する。第1引数にコールバック関数、第2関数にミリ秒単位の時間を渡す
```javascript
const callbackFunc = () => console.log('処理が実行されました!')

// 500ミリ秒後に1度だけ処理を実行できる
setTimeout(callbackFunc, 500) // 処理が実行されました！
```

```javascript
const sampleCallbackFunc = () => {
    console.log('123');

    // setTimeout関数の第1引数に渡したコールバック関数を0ミリ秒後に実行
    setTimeout(() => console.log('456'), 0)

    console.log('789')
}

sampleCallbackFunc() // 123 789 456
```

setTimeout()の第2引数には0ミリ秒を指定していますが、123 789 456と出力される。
setTimeout()がタイマー処理を引き渡している間に次の処理が非同期で実行されているため、コードとは違う並び順で実行される

- [ ] setTimeout(callback, delay)：第2引数に渡された時間が経過したところで1度だけ処理を行う
- [ ] setInterval(callback, during)：第2引数に渡された時間間隔で繰り返し処理を実行、指定した時間が経過すると前回の処理が処理が終了していなくても繰り返しの処理が始まる

## Promise
非同期処理をシンプルに扱うのがPromiseオブジェクトです
実行中の非同期処理を監視し、問題なく処理が完了すればresolve、問題があればrejectを通知する
Promiseオブジェクトは、Pending(待機)、Fulfilled(成功)、Rejected(失敗)の3つの状態を持っています。
| 1 | 2 | 3 |
|:-:|:-:|:-:|
| 状態  | 説明  | 次の処理(コールバック)  |
| Pending  | 何らかの処理を実行している状態、Promiseオブジェクトの初期状態  | ー  |
| Fulfilled  | 処理が成功して終了した状態  | Fulfill状態なら.then()(成功後の処理)を呼び出す  |
| Rejected  | 処理が失敗で終わった状態  | Rejected状態なら.catch()(失敗後の処理)を呼び出す  |

```javascript
const statements = (resolve, reject) => {
    // resoleve() 成功を通知するための関数
    // reject() 失敗を通知するための関数
}

// Promiseインスタンスを作成
const promise = new Promise(statements)
```

statement()の引数であるresolve/rejectはそれぞれの非同期処理の成功と失敗を通知するための関数
statement()の中で、非同期処理が成功した場合にはresolve()を、失敗した場合にはreject()を呼び出します

## Promise.then()

Promiseオブジェクトにおける非同期処理の結果を受け取るのが.then()です
結果が通知されると、次のアクションを関連づけるために使用される
.then()の第1引数に成功時にコールバック関数、第2引数に失敗時のコールバック関数が渡される

```javascript
const promise = new Promise((resolve, reject) => {
    resolve("非同期処理が成功")
})

// 非同期処理が成功した場合の関数を宣言
const SuccessFunc = () => {
    console.log("非同期処理が成功")
}

// 非同期処理が失敗した場合の関数を宣言
const FailureFunc = () => {
    console.log("非同期処理が失敗")
}

// resolve()で非同期処理が成功したという通知を受け取り、then()で成功した場合の処理を実行
promise.then(SuccessFunc, FailureFunc) // 非同期処理が成功
```

resolve()で非同期処理が成功したという通知を受け取った場合、.then()で受け取ったSuccessFunc()が実行される。
また、reject()で非同期処理が失敗したという通知を受け取った場合、.then()で受け取ったFailureFunc()が実行される。

## Promise.catch()
Promiseオブジェクトにおける非同期処理が失敗した場合の結果を受け取るのが.catch()です。

```javascript
const promise = new Promise((resolve, reject) => {
    reject()
})

// 非同期処理が成功した場合の関数を宣言
const SuccessFunc = () => {
    console.log("非同期処理が成功")
}

// 非同期処理が失敗した場合の関数を宣言
const FailureFunc = () => {
    console.log("非同期処理が失敗")
}

promise
    .then(SuccessFunc) // reject()が通知されたため、.then()は無視される(エラーにはならない)
    .catch(FailureFunc) // 非同期処理が失敗
```

## throwとエラー処理
.catch()は非同期処理中に発生した例外(throw)をキャッチすることができます
.then()の中でthrowした場合は、.catch()が呼び出される

```javascript
const promise = new Promise((resolve, reject) => {
    resolve()
})

promise
    .then(() => {
        // エラーオブジェクトを生成し、エラーを投げる
        throw new Error('例外が発生しました');
    })

    // 投げられたエラーを.catch()で受け取り、処理を実行
    .catch((error)) => console.log(error)); // Error: 例外が発生しました
```

## Promise.all()
配列で指定された複数のPromiseオブジェクトすべての非同期処理が成功した場合の結果を受け取るのが.all()です。複数の非同期処理を並列に実行し、その全てが成功した時点で.then()の成功コールバック関数が実行される。いずれか1つでも失敗した場合、.catch()の失敗コールバック関数が実行される

```javascript
const promiseAllObjects = ["aaa", "bbb", "ccc"];

Promise.all(promiseAllObjects)
    // 全ての非同期処理が成功したら.then()の成功コールバック関数を実行
    .then(() => console.log("全ての非同期処理が成功しました");

    // 1つでも非同期処理が失敗したら.catch()の失敗コールバック関数を実行
    .catch(() => console.log("非同期処理は全て成功しませんでした");
```

## Promise.race()
配列で指定された複数のPromiseオブジェクトのうち、最初に状態が変わったという通知を受け取ったものを実行するのがrace()です。複数の非同期処理を並列に実行し、最初に応答があった時点での失敗または成功のコールバック関数が1度だけ実行されます。

```javascript
const promiseRaceObjects = ["aaa", "bbb", "ccc"];

Promise.race(promiseRaceObjects)
    // 最初に状態が変化したという通知を受け取った時点で.then()の成功コールバック関数を実行
    .then(() => console.log("全ての非同期処理が成功しました");
    .catch(() => console.log("非同期処理が成功しませんでした");
```

## Async Function(async/await)
Async Functionを利用すると、Promiseをシンプルに扱うことができます。
await文は、Async Functionの中でのみ使用することができる。
Async Function(async/await)を使用することで、非同期関数を同期関数のように呼び出すことが可能

### async
関数の前にasyncを付けるだけで非同期関数async functionを定義できる

```javascript
// アロー関数で非同期関数async functionを定義
const asyncFunc = async () => {}

// 使用例
const asyncFunc2 = async () => {
    return "これは非同期関数です"
}

// Promiseオブジェクトなので.then()でつないでいくことができる
console.log(asyncFunc2().then((value) => console.log(value))) // これは非同期関数です
```

### await
awaitはasync function内で使用可能。Promiseの状態の通知(resolve/reject)が返されるまで処理を停止して待機し、Promiseの状態が変わったとの通知を受けると次の処理を実行

```javascript
const awaitFunc = async () => {
    
    // Promiseの状態が変わるまで待機
    await Promise インスタンス

    // Promiseの状態が変わると、次の処理を再開
}

// 使用例
// 1000 * num ミリ秒待ってから関数が実行される
const awaitFunc2 = async (num) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolove(`${num}番目の awaitFunc2`);
        }, 1000 * num);
    }).then((num) => console.log(num));
};

// awaitを使用することで、上から順番に処理する
const awaitFunc2 = async () => {
    console.log("1番目の処理”)
    await awaitFunc2(1);
    console.log("2番目の処理”)
    await awaitFunc2(2);
    console.log("3番目の処理”)
    await awaitFunc2(3);

awaitFunc();
// 1番目の処理
// 1番目のawaitFunc2
// 2番目の処理
// 2番目のawaitFunc2
// 3番目の処理
// 3番目のawaitFunc2
}
```