Сбой вывода Dart JavaScript: метод не найден: 'новые задачи:1:0' получатель: экземпляр 'JsClassMirror'

Я перенес удобную библиотеку 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?

2 ответа

Решение

Решение

Оказывается, что у dart2js есть проблемы с зеркальными вызовами методов / конструкторов, которые имеют необязательные позиционные аргументы. Так меняется

class ToDos {
   Sandbox _sandbox;
   ToDos([Sandbox this._sandbox]);
}

в

class ToDos {
   Sandbox _sandbox;
   ToDos(Sandbox this._sandbox); //make the argument non-optional
}

решил мою проблему

Это на самом деле не ответ, так как вы не заявляете, что происходит не так, но некоторые общие советы. В основном, я бы избегал new Symbol() и зеркала, если вы можете легко избежать их, и в этом случае вы можете.

Во-первых, вы должны выяснить, хотите ли вы регистрировать экземпляры модуля или создавать экземпляры по требованию, вы, вероятно, не хотите, чтобы оба были такими, как вы здесь. Если вы зарегистрируете экземпляр, то не можете ли вы просто повторно использовать этот экземпляр? Есть ли start() Нужно производить новые экземпляры как часть своей спецификации? Вы поворачиваетесь и пытаетесь убедиться, что экземпляр все еще не запущен.

Если вам действительно нужно создавать экземпляры, простая фабричная функция устранит необходимость в зеркалах. Так что вместо:

core.register(new ToDos());

Ты пишешь:

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

Если вы все еще хотите использовать зеркала, вы можете очистить использование new Symbol(), Вот несколько рекомендаций:

  • Не используйте символы в качестве ключей, если вы действительно не получаете их от отражающих API, таких как зеркала и noSuchMethod. Просто используйте имя 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;
}
Другие вопросы по тегам