Promiseとasync/awaitについて解説

## はじめに
JSを久々に書くとPromiseを忘れてしまうため、見返せるように記事にしてみました。


## Promiseとは
Promise オブジェクトは、**非同期処理の完了 (もしくは失敗) の結果およびその結果の値**を表します。

### Promiseオブジェクト生成
```js
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('foo');
  }, 300);
});
```

### Promiseを返す関数を生成
```js
function test(time) {
	// Promiseを返す
	return new Promise(
		(resolve ,reject) => {
			setTimeout(() => {
				resolve('foo');
			}, time);
		}
	);
}
// Promiseオブジェクトを作成
const myPromise = test(300);
```


## Promiseの連鎖
Promiseには`promise.then()`, `promise.catch()`, `promise.finally()`の各メソッドが存在する。
これらは promise を返すため、**メソッドチェーン**として使うことができる。

```js
function checkMail() {
	return new Promise((resolve, reject) => {
        // 50%の確率で成功
		if (Math.random() >= 0.5) {
    		resolve('Mail has arrived');
    	} else {
    		reject(new Error('Failed to arrive'));
    	}
	});
}

checkMail()
	.then((mail) => {
		console.log(mail);
	})
	.catch((err) => {
		console.error(err);
	})
	.finally(() => {
		console.log('Experiment completed');
	});
```

### promise.then()
`then()` メソッドは Promise を返します。**最大 2 つの引数**として、
Promise が**成功した場合**と**失敗した場合**の**コールバック関数**を取ります。

### promise.catch()
`catch()` メソッドは Promise を返しますが、**失敗した場合のみ**扱います。
then(undefined, onRejected) の呼び出しと同じ動作です。
簡潔に言うと例外を投げたり、rejectを返すときに使う。

### promise.finally()
`finally()` メソッドは Promise を返します。
Promiseが確立したら、**成功か失敗かにかかわらず**、指定されたコールバック関数が実行されます。


## 静的メソッド
### Promise.all()
複数のPromiseオブジェクトをまとめて処理します。
**全てのPromiseが成功するか、失敗する**まで待ちます。

```js
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
    console.log(values);
    // 出力結果: Array [3, 42, "foo"]
});
```

### Promise.resolve()
`Promise.resolve()` メソッドは、与えられた値で**成功した** Promise オブジェクトを返します。

```js:静的な Promise.resolve メソッドの使用
Promise.resolve('Success').then(function(value) {
    console.log(value); // "Success"
}, function(value) {
    // 呼び出されない
});
```

### Promise.reject()
`Promise.reject()` メソッドは、引数で与えられた理由で**失敗した** Promise オブジェクトを返します。
```js
function resolved(result) {
    console.log('Resolved');
}

function rejected(result) {
    console.error(result);
}

Promise.reject(new Error('fail')).then(resolved, rejected);
// 出力結果: Error: fail
```

## async/awaitとは
`async` および `await` を使用することで、
Promiseベースの非同期の動作を、**Promiseチェーンを明示的に構成する必要なく**、
よりすっきりとした方法で書くことができます。
又、非同期コードに通常の `try/catch` ブロックを使用することができます。

### 書き方の違い
下記のPromise関数を `then/catch` 、 `async/await` で処理の違いをみる。
```js
function test1() {
	return new Promise(resolve => {
		setTimeout(() => {
			resolve('resolved1');
		}, 2000);
	});
}

function test2() {
	return new Promise(resolve => {
		setTimeout(() => {
			resolve('resolved2');
		}, 3000);
	});
}
```

#### then/catchのケース
`test1()`と`test2()`が入れ子になり、ネストが深くなっている。
```js
// 1回目
test1()
	.then((result) => {
		console.log(result);
		// 2回目
		test2()
			.then((result2) => {
				console.log(result2);
			}).catch((e) => {
				console.log(e);
			});
	}).catch((e) => {
		console.log(e);
	});
```

#### async/awaitのケース
ネストが浅くなり、見やすくなった。
```js
(async () => {
	try {
		// 1回目
		const result = await test1();
		console.log(result);
		// 2回目
		const result2 = await test2();
		console.log(result2);
    } catch (e) {
		console.log(e)
    }
})()
```

## おまけ

#### コールバック関数
`resolve` や `reject`で呼ぶ
```js
function test(resolve , reject) {
	if (Math.random() >= 0.5) {
		resolve('Success');
	} else {
		reject('Error');
	}
}
function result(value){ console.log(value); }
function error(value){ console.log(value); }

new Promise(test).then(result, error);
```

promiseオブジェクトを引数へ
```js
function callfunc(fn) {
	const maybePromise = fn();
	// Promiseのみ許可
	if (maybePromise instanceof Promise) {
		return maybePromise.finally(() => {
			console.log('Suceess');
		})
	} else {
		console.log('Error')
	}
}

callfunc(async () => {
	try {
		console.log('start');
	} catch (e) {
		console.log(e);
	}
});
```

## さいごに
以上です。
Promiseの静的メソッドは他にもあり、使い方もそれぞれ存在するため
改めて確認が必要だなと思いました。