Skip to content

Instantly share code, notes, and snippets.

@Leko Leko/0_tc39_study_Leko.md
Last active Oct 9, 2019

Embed
What would you like to do?
#tc39_study - Leko

#tc39_study

#tc39_study - connpass

自己紹介

Screen Shot 2019-10-09 at 13 10 42

3つ喋ります

  • stage3 Hashbang Grammar 2min
  • stage3 Nullish coalescing Operator 1min
  • stage2 Explicit Resource Management 3min

Hashbang Grammar

State: 3(2019/10/08)
Proposal:

tc39/proposal-hashbang: #! for JS

どんな構文のこと?

ファイル冒頭にある#!のこと。概要は下記参照(※2016年の記事、手前味噌)

シバン(shebang)をやっと理解した | WEB EGG

./scripts/do-something のようにCLIからnodeコマンドなしにNode.jsのコードを動かすのに必要

$ echo "console.log('shebang')" > hoge
$ chmod +x hoge 
$ node hoge
shebang
$ ./hoge
./hoge: line 1: syntax error near unexpected token `'shebang''
./hoge: line 1: `console.log('shebang')'

$ echo '#!/usr/bin/env node' > hoge # <---------------------- これ
$ echo "console.log('shebang')" >> hoge
$ ./hoge # <---------------------- nodeのプロセスとして動く
shebang

...ブラウザの世界にいる?

Such hosts strip the hashbang in order to generate valid JS source texts before passing to JS engines currently. This would move the stripping to engines, it does unify and standardize how that is done.

tc39/proposal-hashbang: #! for JS

Node.jsはどうなってた?

shebang、BOMを自前でstripしてた

  function checkScriptSyntax(source, filename) {
    const CJSModule = NativeModule.require('internal/modules/cjs/loader');
    const vm = NativeModule.require('vm');
    const {
      stripShebang, stripBOM
    } = NativeModule.require('internal/modules/cjs/helpers');

    // Remove Shebang.
    source = stripShebang(source); // <----- ここ
    // Remove BOM.
    source = stripBOM(source);
    // Wrap it.
    source = CJSModule.wrap(source);
    // Compile the script, this will throw if it fails.
    new vm.Script(source, { displayErrors: true, filename });
  }

lib/internal/bootstrap/node.js
※v12.xブランチ。masterではもうこの処理消えてる

これからNode.jsはどうなる?

個人的意見

実行処理系によって取り扱いが変わらないように標準化するのはいいことだと思う。
Node.jsとかDeno、Cloudflare workerとかサーバサイドの実行処理系においての話って前提ありきなら妥当だと思う。 ブラウザの世界でshebang混じったコードをimportすることなんてあるかなぁという疑問はある。

Nullish coalescing Operator

State: 3(2019/10/08)
Proposal:

tc39/proposal-nullish-coalescing: Nullish coalescing proposal x ?? y

まえおき

falsyな値という用語を多用します。

falsy な値とは、 Boolean コンテキストに現れたときに false とみなされる値です。

Falsy - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

解決してくれる問題

falsyな値は見逃して、nullとundefinedの時だけ評価される式が書けるようになる

よくやらかすミス

function configure(config) {
  const hoge = config.hoge || defaultConfig
}

フォールバックされる値たち

someVar = 0  // 0はfalsy
someVar = '' // 空文字はfalsy
someVar = false
someVar = null      // nullはfalsy
someVar = undefined // undefinedもfalsy
someVar = NaN       // NaNもfalsy

特に0と空文字で境界値バグやらかしがち

よく使ってたイディオム

function configure(config) {
  const hoge = config.hoge != null ? config.hoge : defaultConfig
}

何が防がれるのか、結局分かりにくくないですか?

これからのJS

function configure(config) {
  const hoge = config.hoge ?? defaultConfig
}

??つけておけばnull, undefinedだけ弾いてくれる。意図しない境界値バグ作らなくて済む

個人的意見

PHP7がでた頃にもNull coalescing operatorで盛り上がったなぁ、としみじみ。
falsyな値の仕様を変えてしまうとBroken webにつながるので、ミスしにくい安全弁を増やしていくのが現実的だよなと思う

Explicit Resource Management

State: 1(2019/10/08)
Champion: Ron Buckton (@rbuckton) Senior SDE for TypeScript MSの人
Proposal:

tc39/proposal-explicit-resource-management: ECMAScript Explicit Resource Management

解決したい課題

  • リソース管理のAPIに一貫性がない
    • ECMAScript Iterators: iterator.return()
    • WHATWG Stream Readers: reader.releaseLock()
    • NodeJS FileHandles: handle.close()
  • リソース確保/解放に関して自分の足を撃ち抜かないような安全弁
  • 適切なスコープを提供する
  • 冗長なテンプレートコードの軽減

多言語での例

  • C#: usingステートメント
  • Java: try-with-resourcesステートメント
  • Python: withステートメント

構文

try (obj) { /* ... */ }
try (const x = expr1) { /* ... */ }
try (const x = expr1, y = expr2) { /* ... */ }

のようにtry (expr) { ...という構文が追加。既存の構文はtry (undefined) {(リソース指定なし)と等価になるそう

Disposeする機能

const resource = {
  [Symbol.dispose] () {
    // リソースの解放
  }
}

こんなのRubyにあったような

IO.open(IO.sysopen("testfile", "w+")) do |io|  
  io.binmode? # => false  
  io.binmode  # => #<IO:fd 8>  
  io.binmode? # => true  
end  

class IO (Ruby 2.6.0)

ブロックを抜けると自動的にリソース(この場合FileDescriptor)を解放する

この構文で改善される既存のよくあるコード

実物見た方が早いのでリンクだけ https://github.com/tc39/proposal-explicit-resource-management#examples

非同期処理ってどうなる?

const getResource = () => ({
  async [Symbol.dispose] () {
    console.log('2')
    // なんかしらの非同期処理
  }
})

try (const r = getResource()) {
  console.log('1')
  throw new Error()
} catch(e) {
  console.log('3')
} finally {
  console.log('4')
}
console.log('5')

出力が1,2,3,4,5ってなるには、リソースの解放を誰かが暗黙的にawaitしないといけない? [Symbol.asyncDispose]が定義されているとそうなるらしい。これってスレッドロックなしに実現可能なのだろうか・・・?
await try (...) { ... }みたいになるのか・・・?try-expressionワンちゃんあるのでは

If we found a [Symbol.asyncDispose] method, we Await the result of calling it.

tc39/proposal-explicit-resource-management: ECMAScript Explicit Resource Management

個人的意見

Generatorとかは違うと思うけど、StreamとかTCP ConnectionとかWebSocket connectionとかを一貫的なAPIで扱えるようになるのはいいなーと思った ただし生存期間の長いリソース(WebSocket)とかとtry-catchは相性悪いような・・・?と感じる

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.