Используя Dart, как правильно вернуть HttpResponse с помощью Future

Я пытаюсь создать очень простой http-сервер, который делает одну вещь. Получив HttpRequest, он выполняет запрос на локальном сервере базы данных и возвращает строку на основе этого запроса.

Я изучаю дартс, и у меня проблемы с пониманием фьючерсов. Я думал, что понял их, но этот пример заставляет меня поверить, что я действительно понятия не имею, как они работают. Итак, я не только ищу решение этой проблемы, но и любые указатели, которые я с радостью приму.

Примечание. Этот код является очень примитивным примером того, что я пытался сделать, и ради обращения к сообществу Stackoverflow я максимально сократил/упростил его, сохранив при этом проблему.

Вот мой код server.dart

import 'dart:io';
import 'package:sqljocky/sqljocky.dart';


final connection = new ConnectionPool(host: 'localhost', port: 3306, user: 'root', password: null, db: 'server1');

main() {

  HttpServer.bind(InternetAddress.ANY_IP_V4, 9090)..then((server) {
    print("serving generic database query on localhost:9090");
    server.listen((request) {
      if (request.method == "GET") {
        request.response.write(getResults());
        request.response.close();
      }
      else {
        request.response.statusCode = HttpStatus.BAD_REQUEST;
      }
    });
  });
}


String getResults() {

  StringBuffer sb = new StringBuffer();
  sb.write("START--");
  connection.query("select name, email, zkey from users")
      ..then((results) {
    results.forEach((row) {
      sb.write(row.toString());
      print(row.toString());
    });
  });

  sb.write("--END");
  print(sb.toString());

  return sb.toString();
}

Поэтому, если я отправлю запрос на этот сервер, он вернет «START----END». Сервер выводит ожидаемый результат запроса, а затем выводит «START----END». Это заставляет меня поверить, что мой ответ на запрос закрывается и возвращается до того, как результат запроса будет обработан.

Итак, независимо от того, скручиваю ли я localhost: 9090/asdf или фактически создаю отправителя HTTP-запроса клиента, я не получаю ожидаемого ответа... который является результатом запроса к базе данных.

заранее спасибо


person jabgibson    schedule 06.08.2014    source источник


Ответы (1)


То, что "START----END" печатается «не по порядку», является поведением фьючерсов, которое поначалу сбивает с толку большинство разработчиков.
Вызов типа connection.query(), возвращающий фьючерс, не выполняется немедленно, а ставится в очередь для последующего выполнения. Текущий поток выполнения продолжается до завершения, а затем очередь обрабатывается одна за другой.

Что не работает в вашем коде, так это то, что вы выполняете асинхронный вызов connection.query() и продолжаете, как если бы это был синхронизирующий вызов. Это никогда не работает в Дарте. Когда вы запускаете асинхронное выполнение, вы не можете вернуться к синхронизации. (насколько я знаю, запланированный async/await должен решить эту проблему).

Подробнее на dartlang.org Петля событий и Dart

РЕДАКТИРОВАТЬ проверенный код

import 'dart:io';
import 'package:sqljocky/sqljocky.dart';

final connection = new ConnectionPool(host: 'localhost', port: 3306, user: 'root', password: null, db: 'server1');

main() {    
  HttpServer.bind(InternetAddress.ANY_IP_V4, 9090)..then((server) {
    print("serving generic database query on localhost:9090");
    server.listen((request) {
      if (request.method == "GET") {
        getResults()
        .then((result) { 
          print('Result: $result'); 
          request.response.write(result);
          request.response.close();
        });
      }
      else {
        request.response.statusCode = HttpStatus.BAD_REQUEST;
      }
    });
  });
}

Future<String> getResults() { 

  StringBuffer sb = new StringBuffer();
  sb.write("START--");
  return connection.query("select name, email, zkey from users") 
  .then((Result results) => results.toList())
  .then((list) {
    list.forEach((row) {
      sb.write(row.toString());
    });
    sb.write("--END");
  })
  .then((_) => sb.toString());
}

См. также ответ Грега на этот вопрос, как читать результаты SqlJocky sqljocky синхронно запрашивает базу данных

person Günter Zöchbauer    schedule 06.08.2014
comment
Теперь я обновил ответ проверенным кодом. Еще одно замечание: вы не должны использовать .. вместо .then (только одна точка), иначе вы соедините все последовательные вызовы .then() с первым будущим, но вы всегда должны подключаться к последнему возвращенному будущему. - person Günter Zöchbauer; 06.08.2014
comment
Выглядит неплохо. Я понятия не имел о построении на возвращении. Спасибо @günter-zöchbauer - person jabgibson; 06.08.2014