Хотя вопросы такого рода задают часто, я думаю, что у меня есть более конкретное ограничение, которое делает проблему немного более интересной. Я пишу клиентское приложение на Dart, используя шаблон MVC. Моя цель проста: прослушивать клики по кнопке, запускать асинхронный запрос к внутреннему API и представлять эти данные пользователю.
Как минимум, у меня есть по одному классу модели, представления и контроллера. Класс модели реализует методы для выполнения запросов и объединения полученных данных. Класс представления имеет интересующее поддерево DOM как поле и реализует методы для управления его элементами. Контроллер имеет по одному экземпляру каждого из классов модели и представления в качестве своих полей и регистрирует обработчики событий в элементах представления. Обработчики событий контроллера запускают вызовы модели для выполнения запросов и возврата данных, которые затем передаются в представление для рендеринга.
Проблема возникает, когда я пытаюсь захватить входящие данные из асинхронного запроса в переменную экземпляра модели. Я хотел бы, чтобы все было хорошо инкапсулировано (именно поэтому я в первую очередь использую Dart), и я бы хотел избежать использования глобальной переменной для хранения данных, поступающих из асинхронного запроса. Минимальный пример моего текущего макета выглядит примерно так, как показано ниже. Для ясности я сделал здесь все поля и методы общедоступными.
// view.dart
class FooView {
// The root element of the view with which we're concerned.
static final Element root = querySelector('#thisView');
FooView() { init(); }
void init() { root.hidden = false; }
// Appends the new data into an unordered list.
void update(List<Map<String,String>> list) {
UListElement container = root.querySelector('ul#dataContainer');
container
..hidden = true
..children.clear();
for ( Map<String,String> item in list ) {
container.append(new LIElement()
..id = item['id']
..text = item['text']
);
container.hidden = false;
}
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
List<Map<String,String>> dataList;
// Makes async request, returning data to caller.
List<Map<String,String>> getData() {
HttpRequest
.getString('example.com/api/endpoint')
.then( (String data) {
dataList = JSON.decode(data);
});
return dataList;
}
}
// controller.dart
class FooController {
FooModel model;
FooView view;
FooController() {
model = new FooModel;
view = new FooView;
}
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = view.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
view.update(model.getData());
});
}
}
Ошибки, которые я вижу, связаны с появлением поля model.dataList
null
в конце всего этого. Мое первое замечание заключается в том, что я не понимаю области действия функций обратного вызова. Как я сначала понял, обратный вызов будет обрабатывать данные запроса, когда они будут получены, и просто установит переменную экземпляра, когда они будут готовы. Возможно, переменная экземпляра имеет псевдоним и модифицируется в рамках обратного вызова, но переменная, которую я хочу вернуть, никогда не затрагивается.
Я подумал о передаче объекта Future
методу представления, который затем просто выполнит обработку и добавит элементы в DOM в качестве побочного эффекта. Этот метод сломал бы мой дизайн MVC (даже больше, чем сейчас в этом минимальном рабочем примере).
Также очень возможно, что я использую асинхронное программирование совершенно неправильно. Если подумать об этом подробнее, то мой асинхронный вызов бесполезен, потому что я в основном делаю блокирующий вызов view.update()
в контроллере при возникновении события. Возможно, мне следует передать запрос Future
контроллеру и запустить оттуда then()
метод запроса при срабатывании обработчика событий.
В какой области Dart находятся функции обратного вызова и как я могу получить из них данные с минимальными побочными эффектами и максимальной инкапсуляцией?
Примечание. Мне не нравится вдаваться в подробности этого часто обсуждаемого вопроса, но я прочитал предыдущие ответы на подобные вопросы безрезультатно.
HttpRequest
в контроллер. Как только я это сделал, у меня есть контроллер, который обрабатываетFuture
и обновляет представление по завершении. Теперь модель просто содержит объекты, которые используются для визуализации представления, вместо того, чтобы включать логику для выполнения запросов. Я думал об использовании Angular или Polymer, но это мое первое приложение для Dart, и я хотел бы сначала изучить основы. - person   schedule 23.07.2014