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 看結果)
沒有留言:
張貼留言