Universal JSで注意すべきJS/Node.jsの違い

# Universal JS

- JavaScript/Node.jsは、同じ言語なのでClient/Server Sideでコードを共有可能
  - Validationなど共有可能
- けれど各moduleのAPIの仕様は必ずしも一致しない
  - 仕様がどこにあるか、を知ることが重要

---

# Q. JavaScriptのTimer APIの仕様はどこにあるでしょう？

---

## A. whatwg

- "setTimeout"と検索
- MDN/MSDNなどが上位にくるので開く
  - 片方しかない場合は、vendorがそのAPIを独自実装している可能性
- vendorがspec決めてる？
  - ex, [MDN](https://developer.mozilla.org/ja/docs/Web/API/WindowTimers/setTimeout)なら「仕様」とい
う欄があるのでそこのリンクを辿ると......
- [whatwg](https://html.spec.whatwg.org/multipage/webappapis.html#timers)が決めていた
  - w3c/whatwgはDOM（html等も含む）の仕様を定義
      - ただしvendorが従っている保証はない
  - EcmaはJSのruntimeのみ定義

---

# Q. JSと[Node.jsのTimer API](https://nodejs.org/api/timers.html)とでは仕様に違いがありますか？

---

## A. JSとNode.jsのTimer APIの違い

- returnの型
  - JSはID(number)
  - Node.jsはTimeout obj
      - timeout.ref(), timeout.unref()という便利な関数がある
- setImmediate API
  - 各種ベンダーの内、MSのみdraftを定義
  - Node.jsも同時期に開発したがspecが全然違う
- `setTimeout(() => console.log('ok'), 0)`
  - Browserでは0msで実行
  - [Node.jsでは1ms後に実行](https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_args)

---

# Q. JavaScriptのConsole APIの仕様はどこにあるでしょう？

---

## A. draft段階（標準化されてない）

- https://github.com/DeveloperToolsWG/console-object/blob/master/api.md
- ブラウザによってconsole.log等で表示される内容や見せ方は異なる（ブラウザによって実装が違う）

---

# Q. Node.jsとEcmaScriptとで、Errorの仕様に違いはありますか？

---

## A. あります

Errorオブジェクトのプロパティの観点で違いをみてみる

- [ECMAScript 2015: Error の定義](http://www.ecma-international.org/ecma-262/6.0/#sec-error-objects)
  - Error.prototype
  - Error.prototype.constructor
  - Error.prototype.message
  - Error.prototype.name
  - Error.prototype.toString()
- [Node独自の追加](https://nodejs.org/api/errors.html#errors_error_propagation_and_interception)
  - error.code
  - error.errno
  - error.syscall
  - stack系はdocに書かれている通りv8独自の追加
- [ベンダー独自の拡張（非標準）](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Error)
  - Error.prototype.description (MS)
  - Error.prototype.number （MS）
  - Error.prototype.fileName （Mozilla）
  - Error.prototype.lineNumber （Mozilla）
  - Error.prototype.columnNumber （Mozilla）
  - Error.prototype.stack （Mozilla/v8）
  - Error.captureStackTrace (v8)
  - Error.stackTraceLimit (v8)

---

## Node.jsのmodule固有のError property

以前は記載がなかったので、Node.jsのdocにPRしました
https://github.com/nodejs/node/pull/10986

module | property
--- | ---
net/http(s) | error.address
net/http(s) | error.port
fs | error.path

```
// with `path` property
$node -e "require('fs').readFile('a file that does not exist', (err, data) => { console.error(err); });"
{ Error: ENOENT: no such file or directory, open 'a file that does not exist'
    at Error (native)
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'a file that does not exist' }

// with `address` and `port` property
$node -e "require('net').connect({port: 100}).on('error', (err) => { console.error(err); });"
{ Error: connect ECONNREFUSED 127.0.0.1:100
    at Object.exports._errnoException (util.js:1022:11)
    at exports._exceptionWithHostPort (util.js:1045:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1087:14)
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 100 }

// with `address` property (without `port` property)
$node -e "require('net').connect({host: 'localhost'}).on('error', (err) => { console.error(err); });"
{ Error: connect EADDRNOTAVAIL 127.0.0.1 - Local (0.0.0.0:54881)
    at Object.exports._errnoException (util.js:1022:11)
    at exports._exceptionWithHostPort (util.js:1045:20)
    at connect (net.js:881:16)
    at net.js:1010:7
    at GetAddrInfoReqWrap.asyncCallback [as callback] (dns.js:62:16)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:81:10)
  code: 'EADDRNOTAVAIL',
  errno: 'EADDRNOTAVAIL',
  syscall: 'connect',
  address: '127.0.0.1' }
```