IE11を考えなくなったClientSide JS


> デスクトップアプリとしての IE11 は 2022/06/16(JST) にサポートが終了されます。

jQuery全盛期を経てIE9, 11の対応を考えながらWebサイト・Webサービスの開発に関わってきた身としては、そりゃもう待望の瞬間です。
遂にIEをサポート外にできる未来が現実になるのです。

これで何が変わるのかというとIEがサポート対象外となれば
Chrome系やSafariなどはすでに最新バージョンのみのサポートとなっていることから
2015年に決まったJSの規格ECMA6とそれ以降のバージョンが標準になっていきます。

今までnodejsでは当たり前に使っていた文や多くの機能がトランスパイルしなくてもそのままClientSideでも使えるようになるのです。
ということでClientSideのJSでよくあるRESTなどのWebAPIを使ったケースがどのようになるか交えながら軽くまとめていきます。

# 積極的に使いたい機能
- [for .. of](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...of) (ECMA2015)
- [async/await](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/await) (ECMA2017)
- [fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API)

## for .. of
他の言語でいうforeach相当ができます。
たまにJS触るとこれができないことを忘れてた。

```javascript
const items = ['foo', 'bar', 'buzz'];
for (const item of items) {
  console.log(item) // foo bar buzz
}
```

## async/await (Promise)
非同期系が簡単に扱えるようになります。

```javascript
async function testFunc(uri)
{
    const response = await fetch(uri).then((res) => {
      console.log(res)
      if(res.ok) {
        return Promise.resolve(res)// Promise
      }
      return Promise.reject(res)// Promise
    })
    return response
}
```

[Promise](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)はjQueryのdeferredと似ていますが少し違っています。Promiseのほうが素直なメソッド名やオブジェクトがreturnされている印象です。

### 気を付けるポイント
- async functionは Promise を返す関数に包んでくれます
- awaitは Promise を受け取り処理完了まで同期的に待ってPromiseを剥いて中身を渡してくれる
- async内で await が使える

## fetch
JSではなくブラウザ側で用意されているAPIです。
XHRを高レイヤー層として扱えることができます。

Requestオブジェクトを渡せることができるようになって
Responseオブジェクトを最終的に返すPromiseを受け取るようになります。
WebAPIにPOSTでJSONを投げてJSONが返ってくる例です。

```javascript: fetchTask.js
async function fetchTask (reqData) {
  const headers = new Headers()
  headers.append('Content-Type', 'application/json')
  const request = new Request(
    'http://localhost/200.json',
     {
       method: 'POST',
       headers: headers,
       body: JSON.stringify(reqData)
     }
  )
  const response = await fetch(request).catch(() => {throw new Error('connect error')})
  if (response.ok === false) { 
    throw new Error('HTTP Error') 
  } 
  const data = await response.json().catch(() => {throw new Error('parser error')}) 
  // アプリ側で独自に定義しているデータ型があればレスポンスデータの中身を見て検査
  if (data.result && data.result === 'OK') {
    return data 
  }
  throw new Error('app error') // WebAPI側エラー
}
```

### 気を付けるポイント
- ネットワーク接続エラーはErrorとしてthrowされる
- HTTP Status の異常系(40x, 50x系とか)も正常系と同じくResponseを受け取る
→ 受け取ってからresponse.statusなどを見て判断が必要
- JSONパーサー失敗時はPromiseでErrorがthrowされる

## fetchTask 使用側の書き方
どちらも非同期扱いなのでfetchTaskが終わるまで待つことはなくすり抜けるような感じになります。

### async functionで扱う例
async function でさらにくるんで実行するスタイルです
```javascript
(async () => {
  try {
    const data = await fetchTask({id: 9999})
    console.log(data)
  } catch (err) {
    console.error(err.message)
  } finally {
    console.log('finally fired')
  }
})()
```
try..catchがいつもの同期的なコードで書けます。
わかりやすい

### Promiseとして扱う例
こちらはPromiseでつないでいくスタイルです
```javascript
fetchTask({id: 9999})
  .then(data => {console.log(data)}) 
  .catch(err => {console.error(err.message)}) 
  .finally(() => {console.log('finally fired')})
```
jQuery使っていた人は親近感わいてつい使いたくなるけど
基本 async/await になれてfetchTaskでの例のようなごく一部分だけ使う程度で良いと思います。


# ブラウザ互換表
他にもいろいろな機能が使えるのでブラウザ互換性をチェックしつつ新時代を迎えてみてください。

ECMA6 compatibility table
https://kangax.github.io/compat-table/es6/