0

便利な JS ライブラリを Dart に移植しました: dartscale。その機能の重要な部分は、次のように分類できます。

final Map<Symbol, ClassMirror> _registeredModules = new Map<Symbol, ClassMirror>();

register(module, [String moduleName]) {
   final uniqueModuleName = moduleName != null ? moduleName : module.runtimeType.toString();
   final Symbol uniqueModuleIdentifier = new Symbol(uniqueModuleName);

   if (_registeredModules.containsKey(uniqueModuleName)) {
     throw new StateError("Module ${moduleName} already registered!");
   }

   final ClassMirror mirror = reflect(module).type;
  _registeredModules[uniqueModuleIdentifier] = mirror;
}

start(Symbol moduleName, String id, options) {
   if (!_registeredModules.containsKey(moduleName)) {
      throw new StateError("Module ${moduleName} not registered!");
   }

   final ClassMirror mirror = _registeredModules[moduleName];
   final Symbol moduleId = id != null ? new Symbol(id) : moduleName;
   final Sandbox sandbox = new Sandbox(this.mediator);

   if (_runningModules.containsKey(moduleId)) {
      throw new StateError("Module with id #${moduleId} already running!");
   }

   final InstanceMirror moduleInstance = mirror.newInstance(new Symbol(''), [sandbox], null);
   moduleInstance.invoke(new Symbol("start"), [options]);

   _runningModules[moduleId] = moduleInstance;
}

私も例を提供します

part of example;

class ToDos {

    Sandbox _sandbox;

    DivElement _contentEl;
    int _nextToDoId = 0;

    UListElement _todoList;

     ToDos ([Sandbox this._sandbox]);

     start([Map options]) {
         this._initLocalStorage();

         var html = ['<div id="module-todos">',
                       '<form>',
                          '<input type="text" class="input-medium">',
                          '<button type="submit" class="btn">Add</button>',
                       '</form>',
                       '<ul>',
                       '</ul>',
                     '</div>'].join('');

         this._contentEl = new Element.html(html);
         this._todoList = this._contentEl.query('ul');

         options['containerEl'].append(this._contentEl);

         window.localStorage.keys.forEach((key) => this._renderToDo(key));

         this._setupEvents();

         this._sandbox.channel('navigationbar').topic('filter').listen((filterContent) {
             this._filter(filterContent);
         });

        this._sandbox.channel('navigationbar').topic('clearfilter').listen((filterContent) {
           this._todoList.queryAll('li span').forEach((element) => element.parent.classes.remove('hide'));
        });
    }

    stop() {
        this._contentEl.remove();
    }

    _initLocalStorage() {
        if (window.localStorage.keys.length == 0) {
            var map = {
                "1": {
                    "subject": "Groceries: Banas and Apples",
                    "isDone": false
                },
                "2": {
                    "subject": "Taxes: take care of them",
                    "isDone": false
                },
                "3": {
                    "subject": "Bring out trash",
                    "isDone": false
                }  
            };

            for (var key in map.keys) {
                window.localStorage[key] = stringify(map[key]);
                this._nextToDoId++;
            }
        }
        else {
           for (var key in window.localStorage.keys) {
              var intKey = int.parse(key);

              if (intKey > this._nextToDoId) {
                  this._nextToDoId = intKey;
              }

              this._nextToDoId++;
           }
       }
   }

   _setupEvents() {
       var input = this._contentEl.query('input');

       input.onKeyDown.listen((event) {
          if (event.keyCode == KeyCode.ENTER) {
              event.preventDefault();

              this._addToDo(input.value);
              input.value = '';
          }
       });

       this._contentEl.query('button[type="Submit"]').onClick.listen((event) {
           event.preventDefault();

           if (input.value.length > 0) {
               this._addToDo(input.value);
               input.value = '';
           }
       });

       this._todoList.onClick.listen((MouseEvent event) {
           var el = event.target;

           if (el.classes.contains('icon-remove')) {
               this._deleteToDo(el.parent);
           }
           else if (el.classes.contains('icon-ok')) {
               this._toggleToDoDone(el.parent);
           }
       });
   }

   _renderToDo(id) {
       var todoObject = parse(window.localStorage[id.toString()]);

       var html = ['<li class="record-todo ', todoObject["isDone"]?"done":"",'" data-id="', id,'">',
                      '<span>', todoObject["subject"], '</span>',
                      '<i class="icon icon-ok"></i>',
                      '<i class="icon icon-remove"></i>',
                  '</li>'].join('');

       this._todoList.append(new Element.html(html));
   }

   _addToDo(text) {
       var todoJson = stringify({
           "subject": text,
           "isDone": false
       });

       window.localStorage[this._nextToDoId.toString()] = todoJson;
       this._renderToDo(this._nextToDoId);

       this._nextToDoId++;
   }

   _deleteToDo(todoLIElement) {
       window.localStorage.remove(todoLIElement.dataset["id"]);

       todoLIElement.remove();
   }

   _toggleToDoDone(todoLIElement) {
       var done = !todoLIElement.classes.contains('done'); 
       var id = todoLIElement.dataset["id"];
       var todoObject = parse(window.localStorage[id]);
       todoObject["isDone"] = done;
       window.localStorage[id] = stringify(todoObject);

       if (done) {
          todoLIElement.classes.add('done');
       }
       else {
          todoLIElement.classes.remove('done');
       }
   }

   _filter(content) {
       this._todoList.queryAll('li span').forEach((element) {
            if (element.innerHtml.contains(content)) {
                element.parent.classes.remove('hide');
            }
            else {
               element.parent.classes.add('hide');
            }
       });
   }
}

私のApp.dartで

library example;

import 'dart:html';
import 'dart:json';
import '../lib/dartscale.dart';

part 'dart/ToDos.dart';

main () {
    var core = new Core();
    core.register(new ToDos());

    core.start("ToDos", "ToDos", {
        "containerEl": query('body > .container')
    });
}

Dart2jsのバグ?

4

2 に答える 2

0

何が問題なのかを述べていないため、これは実際には答えではありませんが、一般的なアドバイスです。ほとんどの場合、new Symbol()それらを簡単に回避できる場合は回避してミラーリングしますが、この場合は回避できます。

最初に、モジュール インスタンスを登録するか、オンデマンドでインスタンスを生成するかを決定する必要があります。おそらく、ここにいるように両方を望んでいるわけではありません。インスタンスを登録すれば、そのインスタンスを再利用することはできませんか? start()仕様の一部として新しいインスタンスを生成する必要がありますか? 振り返って、インスタンスがまだ実行されていないことを確認しようとします。

本当にインスタンスを生成する必要がある場合は、単純なファクトリ関数を使用するとミラーが不要になります。したがって、代わりに:

core.register(new ToDos());

あなたが書く:

core.register('ToDos', () => new ToDos());

それでもミラーを使用したい場合は、 の使用をクリーンアップできますnew Symbol()。いくつかの推奨事項を次に示します。

  • そもそもミラーや noSuchMethod などのリフレクション API から実際にシンボルを取得する場合を除き、シンボルをキーとして使用しないでください。String 名またはおそらく runtimeType を使用してください。あなたの場合、シンボルと文字列を_registeredModulesマップのキーとして混在させています。これは、モジュールが登録されていないように見えるなど、おそらくいくつかのバグを引き起こしています。(チェックモードでテストしていますか?)
  • 使わないnew Symbol('name')、使うconst Symbol('name')
  • メソッドを直接呼び出すことができる場合は、InstanceMirror.invoke、getField、または setField を使用しないでください。あなたのコードでは、置き換えることができます

    moduleInstance.invoke(new Symbol("start"), [options]);
    

    moduleInstance.reflectee.start(options);
    
  • 工場は悪くない。型インスタンスからコンストラクターを呼び出すのはいいことですが、それまでは、Dart でファクトリを登録するのはかなり軽量です。

これらの提案を含むコードは次のとおりです。

typedef Object Factory(Sandbox sandbox);

final Map<Symbol, Factory> _registeredModules = new Map<Type, Factory>();

register(Type type, Factory factory) {
   if (_registeredModules.containsKey(type)) {
     throw new StateError("Module $type already registered!");
   }
   _registeredModules[type] = factory;
}

start(Type type, options) {
   if (!_registeredModules.containsKey(type)) {
      throw new StateError("Module $type not registered!");
   }
   if (_runningModules.containsKey(type)) {
      throw new StateError("Module $type already running!");
   }
   Sandbox sandbox = new Sandbox(this.mediator);    
   var module = _runningModules[type](sandbox)..start(options);
   _runningModules[type] = module;
}
于 2013-07-29T02:59:30.263 に答える