2019年9月18日 星期三

dart to js Promise

dart 可以透過 dart2js 將程式碼轉換成 Javascript:
          dart2js    source.dart   -o      source.js
如果用不到 source map 檔案 (source.js.map), 可以進一步產生優化的輸出檔:
          dart2js    source.dart   -o      source.js   --no-source-maps    -O2
在 Javascript 的語法中, 實現非同步程式運作可以用 async/awiat 或是用 Promise 的  then 回調函式(callback function)去操作將來的傳回值, 用 async/await 程式碼比較乾淨,也容易理解, 但有些時候還是免不了要用 Promise 的方式(resolve or reject)去完成, dart 的類型Completer 物件就是一個類 Promise 物件,  裡面的 complete 方法可看成是 Promise 的 resolve, 而 completeError 自然就是 Promise 的 reject 方法, 裡面的 future 就是一個 Promise 物件, 換句話說 Completer 實際上是將 Promise 包裝成一個獨立物件, 因此可以這樣用:
       import 'dart:async';
       void setTimeout(callback, int mS) => Timer(Duration(milliseconds: mS),  callback);
       void main ( ) async {
            final c = Completer( );
            setTimeout( ( ) => c.complete("Done!"), 500); // compete after 500mS
            try {
                final result = await  c.future;
                print('OK:$result');
           } catch (error) {
                print('<$error>');
           }
       }
如果這樣子用不習慣, 可以採用熟悉的 resolve 與 reject, 先包裝成一個原型後, 再加以實現:
     import 'dart:async';
     abstract  class   _Promise { // 原型, 介面類型
            final field;
            resolve(_)  => this.field.complete(_);
            reject(_)     => this.field.completeError('error:$_');
            call ( )        => this.field.future; // functor to return future
            _Promise(this.field); // 建構式
     }
     class  Promise  extends  _Promise { // 繼承原型加以實現, 用 Completer 去初始化原型
               Promise( ) : super( Completer( ) ); 
     }
 也可以用工廠建構式搭配帶名建構式直接實現 Promise 類型:
     import 'dart:async';
     class Promise {
           final field;
           resolve(_)  => this.field.complete(_);
           reject(_)     => this.field.completeError('error:$_');
           call ( )        => this.field.future; // functor to return future
           Promise._(this.field); // 帶名建構式
           factory  Promise( ) => Promise._( Completer( ) );  // 用工廠建構式傳回物件, Completer( ) 初始化 this.field
     }
其實可以更簡單一點, 直接初始化 field = Completer( ), 再把需要用到 method 接起來:
     import 'dart:async';
     class Promise {
           final field = Completer( );
           resolve(_)  => this.field.complete(_);
           reject(_)     => this.field.completeError('error:$_');
           call ( )        => this.field.future; // functor to return future
     }
     void setTimeout(callback, int mS) => Timer(Duration(milliseconds: mS),  callback);
     void main ( ) async {
            final c = Promise( );
            setTimeout( ( ) => c.resolve("Done!"), 500); // resolve after 500mS
            try {
                final result = await  c( ); // 呼叫  call 函式回傳 future, 等待完成
                print('OK:$result');
           } catch (error) {
                print('<$error>');
           }
     }
顯而易見, 上述方式雖然達到了目的,  但經過物件層層堆疊, 執行效率必然變差了.
dart 語言不但能轉換成 Javascript, 經由 import 'dart:js' 的函式庫後, 透過 context  與中介方法 callMethod 就能呼叫 Javascript 原始碼, 以 console.log 呼叫為例, 將它包裝成一個類型方便使用:
     // test.dart
     import 'dart:js';
     class JS {
            final field;
            JS._(this.field);
            factory JS([String _='']) => _.length>0 ? JS._(context[_]) : JS._(context);
            void log(String s)   => this.field.callMethod('log', [s]);// 參數必須放在 List [ ] 裏面
            call (String method, String s)=> this.field.callMethod(method, [s]);// functor
     }
     void main( ) {
          final console = JS('console');// 初始化 context
          console.log( "Hello");    // 透過 log 方法
          console('log',   'Hello2');// 透過 functor 呼叫 .log
     }
用 dart2js 編譯轉換成 Javascript:
      dart2js   test.dart   -o test.js    -O2   --no-source-maps
上述透過 dart2js 編譯過的程式碼 test.js 只能在瀏覽器內執行, 因此還要寫一個 html檔案:
<html><head><meta charset='utf-8'></head><body>
    <script type='application/javascript' src='test.js'></script>
</body></html>
將以上內容存檔成 index.html, 瀏覽器開啟 index.html 就能執行(在 Chrome 相容性比較好, 打開開發工具, 點選 console 看結果)

沒有留言:

張貼留言

使用 pcie 轉接器連接 nvme SSD

之前 AM4 主機板使用 pcie ssd, 但主機板故障了沒辦法上網, 只好翻出以前買的 FM2 舊主機板, 想辦法讓老主機復活, 但舊主機板沒有 nvme 的界面, 因此上網買了 pcie 轉接器用來連接 nvme ssd, 遺憾的是 grub2 bootloader 無法識...