Язык программирования Dart

Использование API для фьючерсов

4 February 2014 г. 23:11:09

Использование фьючерсов для асинхронных операций

Перевод статьи Shailen Tuli

 

Dart это одно поточный язык программирования. И если выполнение какой-то части кода блокирует выполнение (например, ожидание выполнения трудоемкой операции или блокирование ввода/вывода) программа ощутимо подвисает.  Асинхронные операции позволяют вашей программе работать без блокирование. Для предоставления асинхронных операций Dart использует объекты называемые фьючерсами (Future object).

 ~cut~

Введение

Что такое фьючерсы

Использование фьючерсов

Последовательность событий при выполнении кода

Обработка ошибок при работе с фьючерсами

Вызов нескольких функций которые возвращают фьючерс

  

Введение.

Давайте рассмотрим код который может вызывать зависание программы:

import 'dart:io';
 void printDailyNewsDigest() {
  File file = new File("dailyNewsDigest.txt");
  print(file.readAsStringSync());
}
 
 void main() {
  printDailyNewsDigest();
  printWinningLotteryNumbers();
  printWeatherForecast();
  printBaseballScore();
}

Наша программ читает ежедневные новости новости из файла,  dailyNewsDigest.txt, выводит из и выводет некоторые другие элементы которые могут быть интересны пользователю

 

<Contents of dailyNewsDigest.txt>
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny.
Baseball score: Red Sox 10, Yankees 0

 

В нашем коде есть проблемы: readAsStringSync() блокирует выполнение и оставшая часть кода будете выполнена только после того как readAsStringSync() вернет содержимое файла, сколько бы много времени это не занимало. И если чтение файлов занимает много времени, пользователи просто ждут, гадая выиграли ли они в лотерее, или какая погода будет завтра, или кто выиграл сегодняшнюю игру. Не хорошо.

Чтобы помочь приложению быть более отзывчивым,  авторы библиотеки Dart используют асинхронные модели при определении функий, для выполнения большей части работы. Эти функции возвращают значения используюя фиючерсы.

 

Что такое фьючерс

Фьючерс предcтавляет собобой средство для получения значения кода-то в будушем. Когда вызывается функция которая является фьючерсом происходит две вещи:

1. Функция помещается в очередь на выполнение и немедленно возвращается  неисполненый объект фьючерса.

2. Позже, когда значение уже доступна, объект фьючерса выполняется с этим значением ( или с ошибкой, но это обсудим позже).

Чтобы получить значение, которое возвратит фьючерс, для регистрации колбэка используется метод then().

Использование фьючерсов

Давайте перепишем printDailyNewsDigest() чтобы получить содержание файла асинхронно:

import 'dart:io';
import 'dart:async';
 
void printDailyNewsDigest() {
  File file = new File("dailyNewsDigest.txt");
  Future future = file.readAsString();
  future.then((content) {
    print(content);
  });
}

Теперь функция  printDailyNewsDigest() использует функцию readAsString(), которая теперь не блокирующая. Вызов readAsString() помещается в очередь на выполнение но не останавливает выполнение остальной части кода. Программа выводит лотерейные номера, прогноз погоды и счет в бейсболе. Когда readAsString() закончит чтение файла новостей, программа выведет ее содержание. Если выполнение функции readAsString() займет некоторое время на свое выполнение - ничего страшного, пользователи смогут почитать другую информацию пока новости будут выводиться.

Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny.
Baseball score: Red Sox 10, Yankees 0
<Contents of dailyNewsDigest.txt>

Последовательность событий при выполнении кода

  1. Программа попадает в функцию main(), которая вызывает printDailyNewsDigest(), которая в свою очередь помещает в очередь задание на чтение файла. После этого вызываются остальные функции вывода и выходит из функции main(), но выполнение программы продолжается.
  2. Планируется работа для выполнения readAsString(), и содержание файла считывается в память. Когда файл полностью считывается, фьючерс завершает работу с файлом.
  3. С помощью зарегистрированной функции then() вызывается и выводится содержимое файла новостей.

Вызов then() возвращает новый фьючерс, который выполняется со значением, которое вернула функция then(). Это значит что вызов then() может быть исполнено по цепочук ( мы увидим примеры далее).

Обработка ошибок при работе с фьючерсами

Если функция которую запускает фьючерс выполняется с ошибкой, фьючерс then() так же выполнится с ошибкой. Мы можем перехватить эту ошибку используя catchError():

void printDailyNewsDigest() {
  File file = new File("dailyNewsDigest.txt");
  Future future = file.readAsString();
  future.then((content) => doSomethingWith(content))
        .catchError((e) => handleError(e));
}

Если файл dailyNewsDigest.txt не существует или он не доступен для чтения, код выше выполнится следующим образом:

Фьючерс readAsString() выполняется с ошибкой.

Фьючерс then() выполняется с ошибкой.

Колбэк catchError() обрабатывает ошибку, фьючерс catchError() выболняется нормально, и ошибка не возникает.

Так же как и then(), catchError() возвращает новый фьючерс который выполяется со значением которое возвращает колбэк.

Вызов нескольких функций которые возвращают фьючерс

Рассмотрим три функции  expensiveA(), expensiveB(), expensiveC() которые возвращают фьючерс. Вы можете вызывать их последовательно (одна функция запустится когда предыдущая завершится), или вы можете дождаться выполнения всех функций и что-то сделать с получившимся в результате значением. Интерфейс фьючерсов достаточно гибок для работы в обоих случаях.

Последовательный вызов используя then()

Когда надо выполнять функции в определенном порядке используется последовательный вызов then()

expensiveA().then((aValue) => expensiveB()) 
            .then((bValue) => expensiveC()) 
            .then((cValue) => doSomethingWith(cValue))

Вложенные колбэки тоже работаю , но их значительно сложнее читать, и это не путь Дарта.

Ожидания выполнения нескольких фьючерсов используя Future.wait()

Если порядок выполнения функций не важен, вы можете использовать Future.wait() для обработки фьючерсов без явного использования последовательного вызова функций.

Функция срабатывает лишь в одном случае, когда все из них выполннеы со значением. Future.wait()  возвращает новый фьючерс. Этот фьючерс выполняется со списком значений предоставленным каждой функцией. 

Future.wait([expensiveA(), expensiveB(), expensiveC()])
      .then((List responses) => chooseBestResponse(responses))
      .catchError((e) => handleError(e));

Если любая из вызванных функций выполняется с ошибкой, фьючерс возвращаемый Future.wait()  так же выполняется с ошибкой. Для обработки ошибки используется  catchError().

 


Оставьте свой комментарий

comments powered by Disqus
Меню

Cult of digits 2014 Яндекс.Метрика