2016-06-08 2 views
2

Возможно ли заблокировать вызов функции, который возвращает будущее?Создание будущего блока до его завершения

Я был под впечатлением от звонка .then(), но это не то, что я вижу в своем выпуске.

print("1"); 
HttpRequest.getString(url).then((json) { 
    print("2"); 
}); 
print("3"); 

Что я вижу в моем выходе:

1 
3 
2 

Метод getString не имеет async, который позволил бы мне await его и then выполняет асинхронно в любом случае.

static Future<String> getString(String url, 
     {bool withCredentials, void onProgress(ProgressEvent e)}) { 
    return request(url, withCredentials: withCredentials, 
     onProgress: onProgress).then((HttpRequest xhr) => xhr.responseText); 
    } 

Как сделать блокированию без размещения бесконечного времени цикла перед пунктом 3 ждет шага 2 будет завершен (не то, что он будет работать в любом случае из-за одного потоком природы Dart)?

выше HttpRequest загружает config.json файл, который определяет, как все работает в приложении, если запрос на поле в конфигурации выполняется до того, как файл config.json выполняется загрузка, это приводит к ошибкам, так что нужно ждать, пока файл загружается, прежде чем я разрешу вызывать геттеры в полях класса, или геттерам нужно ждать однократной загрузки файла config.json.

Update, это то, что я в конце концов сделал, чтобы заставить его работать после того, как Гюнтер предложил мне использовать Completer:

@Injectable() 
class ConfigService { 

    Completer _api = new Completer(); 
    Completer _version = new Completer(); 

    ConfigService() { 

     String jsonURI = 
      "json/config-" + Uri.base.host.replaceAll("\.", "-") + ".json"; 
     HttpRequest.getString(jsonURI).then((json) { 

      var config = JSON.decode(json); 
      this._api.complete(config["api"]); 
      this._version.complete(config["version"]); 

     }); 
    } 

    Future<String> get api { 
     return this._api.future; 
    } 

    Future<String> get version { 
     return this._version.future; 
    } 

} 

И где я использую ConfigService:

@override 
ngAfterContentInit() async { 

    var api = await config.api; 
    var version = await config.version; 

    print(api); 
    print(version); 

} 

Теперь я получаю блокирующие функции без фактического блокирования.

ответ

2

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

Один из способов цепи then

print("1"); 
HttpRequest.getString(url) // async call that returns a `Future` 
.then((json) { // uses the `Future` to chain `(json) { print("2"); }` 
    print("2"); 
}); 
print("3"); // not chained and therefore executed before the `Future` of `getString()` completes. 

асинхронный вызов только планирование кода для последующего выполнения. Он будет добавлен в очередь событий, и когда обрабатываемые задачи будут обработаны, он сам будет выполнен. После запланированного асинхронного вызова будет продолжен код синхронизации `print (« 3 »).

В вашем случае HttpRequest.getString() назначает вызов вашему серверу и регистрирует (json) { print("2") в качестве обратного вызова, который будет вызываться при поступлении ответа от сервера. Дальнейшее выполнение приложения не останавливается до тех пор, пока не поступит ответ, и нет способа сделать это. Вместо этого происходит то, что код синхронизации продолжает выполняться (print("3")). Если ваш текущий исполняемый код синхронизации достигает своего конца, следующая задача запланирована так же.

then() планирует ввести код (json) { print("2"); }, выполненный после getString() завершен.

ждет

async и await просто сделать асинхронный код выглядеть больше как код синхронизации, но в остальном это совершенно так же и будет переведен под капотом на xxx.then((y) { ... }).

+0

Ммм, довольно рассол! Внутри загружаемого json-файла есть URL-адрес, который мне нужно загрузить в ConfigService. NG2 загружается так быстро, что к тому времени, когда он начнет обстрелы RPC на этот URL для данных, файл 'config.json' все еще загружается, вызывая 404 ошибки. –

3

Я не уверен, я понимаю, что вы пытаетесь достичь, но она смотрит на меня, вы хотите сделать это:

myFunction() async { 
    print("1"); 
    final json = await HttpRequest.getString(url); 
    print("2"); 
    print("3"); 
} 
2

async заявление требуется только в функции потребителя. Другими словами, функции производителя не должны иметь async, им нужно вернуть Future.

вы должны быть в состоянии сделать это:

Future consumerFunc() async { 
    print("1"); 

    var response = await HttpRequest.getString(url); 

    print("2"); 

    print("3"); 
} 

и это должно привести к:

1 
2 
3 

Примечание: await заменяет then метод

Смежные вопросы