Node.js
ECMAScript
WHATWG
UniversalJS

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

More than 1 year has passed since last update.


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なら「仕様」とい
      う欄があるのでそこのリンクを辿ると......




  • whatwgが決めていた


    • w3c/whatwgはDOM(html等も含む)の仕様を定義


      • ただしvendorが従っている保証はない



    • EcmaはJSのruntimeのみ定義





Q. JSとNode.jsのTimer APIとでは仕様に違いがありますか?



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)





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



A. draft段階(標準化されてない)



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



A. あります

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



  • ECMAScript 2015: Error の定義


    • Error.prototype

    • Error.prototype.constructor

    • Error.prototype.message

    • Error.prototype.name

    • Error.prototype.toString()




  • Node独自の追加


    • error.code

    • error.errno

    • error.syscall

    • stack系はdocに書かれている通りv8独自の追加




  • ベンダー独自の拡張(非標準)


    • 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' }