【Flutter/Dart】Futureの基本的な使い方|非同期処理 part1

Future
目次

Futureとは?

結論

Futureを使えば、非同期処理を実行できます。また、非同期処理のある時点で戻り値(future)なる値を、別のプログラムに用いて使用することもできます。

この説明だけでは分かりにくいので、非同期処理のメリットと仕組みについて解説した後で、Futureについて解説していきます。

同期処理/非同期処理とは?

プログラムのタスク(処理)を実行する方法には同期処理と非同期処理の2種類があります。

それでは同期処理、非同期処理の解説を順にしていきます。

同期処理(sync, synchronous)

同期処理

同期処理(sync, synchronous)では、複数のタスクを上から順に1つずつ実行します。

図のように3つのタスクがあった場合、同期処理ではタスクAの処理が完了するまでタスクB, Cの処理の実行に移れません。

同期処理の例(Futureなし)

import 'dart:io'; //sleep関数をインポート

void main() {
  task1();
  task2();
  task3();
}

void task1(){
  print('task1 完了');
}

void task2() {
  print('task2 処理中');
  sleep(Duration(seconds: 3));
  print('task2 完了');
}

void task3(){
  print('task3 完了');
}

//出力結果の順番
//task1 完了
//task2 処理中
//task2 完了
//task3 完了

このコードでは、task2にsleep関数を使用し、3秒後に「task2 完了」が出力するようにしています。また同期処理のコードなのでtask2の処理が完了するまで、task3の処理は実行されません。

>>【Dart】sleep関数の使い方|dart:io library

非同期処理(async, asynchronous)

非同期処理1

非同期処理(async, asynchronous)を使えば、複数のタスクを同時進行で実行できます。

図のようにタスクAの処理中にタスクB, Cの処理を同時に実行でき短時間で処理を完了できます。ユーザビリティに優れており、至る所で非同期処理は使われています。(例:ブログを開くと文章がずらっと表示された後に、遅れてアイキャッチ画像が表示される)

非同期処理の例(Futureあり)

//Future.delayed()を使用する場合
void main() {
  task1();
  task2();
  task3();
}

void task1() {
  print('task1 完了');
}

void task2() {
  print('task2 処理中');
  Future.delayed(Duration(seconds: 3), () {
    print('task2 完了');
  });
}

void task3() {
  print('task3 完了');
}

//出力
//task1 完了
//task2 処理中
//task3 完了 
//task2 完了

このコードでは、task2に非同期処理のFuture.delayed(後で解説)を使用し、3秒後に「task2 完了」が出力するようにしています。また非同期処理なのでFuture.delayedの処理中に、task3の処理を実行できます。

非同期処理2

ただ全ての処理が同時に実行されるわけではありません。なぜなら、非同期処理によって生成した戻り値(future)を別のプログラムで使用する際、その処理が完了する(戻り値が生成される)のを待つ必要があるからです。

図でイメージすると、タスクBの戻り値をタスクDで使用するには、タスクBの処理が完了するのを待たなければいけません。

それでは、これらの理解を踏まえた上で「Future」について解説していきます。

Futureには3つの状態がある

Future

非同期処理で戻り値(value/error)を生成したり、生成した戻り値をプログラムで使用するのにFutureを使います。また、Futureの戻り値を「future」と呼び、Future型のオブジェクトとして扱います。(以後、Futureの戻り値をfutureと呼びます)

Futureには3つの状態があります。

  • 未完了:プログラムの処理中
  • 完了:成功(value)
  • 完了:失敗(error)

1つ目は、future(戻り値)がまだ生成されていない処理中の状態です。そして2つ目、3つ目の状態はプログラムの処理が終わり、futureである「value」を生成できた状態と、処理が上手くいかず「error」が起きた状態があります。

Future型の宣言/非同期関数の定義

宣言

Future<型> オブジェクト名 = Future型のオブジェクト;

Future型のオブジェクトの宣言は、変数の宣言と同じです。

>>【Dart】static変数とdynamic変数の使い方|型と宣言

非同期関数の定義

//void型の非同期処理関数
void 非同期関数名(){
  (実行する処理) //非同期処理を実行できる
};

//future(戻り値)のある場合
Future<型> 非同期関数名(){
  (実行する処理) //非同期処理を実行できる
  return 戻り値;
};

非同期処理を実行する関数を非同期関数と呼びます。非同期関数は通常の関数/メソッドと同じように定義できます。

>>【Dart】関数(メソッド)の使い方|定義・戻り値・引数・キーワード引数・アロー関数

また、非同期関数はasync/awaitを使うことでより簡単に定義できます。

基本となるコンストラクタ

  • Future():基本となるコンストラクタ
  • Future.delayed():時間を遅らせて指定した処理を実行できる

Future()

Future(コールバック関数);
//例
Future((){
  print('Hello World');
});

Futureの最も基本となるコンストラクタで、非同期処理を実行できます。引数にコールバック関数を使用し、実行する処理を定義します。

Future.delayed()

Future.delayed(Duration duration, コールバック関数);
//例
Future.delayed(Duration(seconds: 3), () {
  print('Hello World'); //処理が始まって3秒後に出力される
});

Future.delayedを使えば、時間を遅らせて指定した処理を実行できます。遅らす時間を指定するにはDurationクラスを使用します。また、コールバック関数で実行する処理を定義します。

>>【Dart】Durationの基本的な使い方

基本となるメソッド

  • then():futureが生成された際、生成されたfutureをコールバック関数を呼び出して使用できる

then(コールバック関数)

future(戻り値)を持つ非同期処理.then((future){
    (実行する処理) // futureを使用できる
  }
);
//例
void main() {
  greeting().then((value) {
    print('thenメソッドで処理中...');
    print(value);
  });
}

Future<String> greeting() {
  return Future.delayed(Duration(seconds: 3), () {
    print('greetingで処理中...');
    return 'Hello World';
  });
}

//出力
//greetingで処理中...
//thenメソッドで処理中...
//Hello World

thenメソッドを使えば、future(戻り値)を生成する非同期処理が完了した後に、コールバック関数を用いて生成したfutureを別のプログラムに使用できます。

また、thenメソッドのコールバック関数の引数に、futureに適当な名前を付けて代入します。

この例の場合、非同期関数(greeting関数)のfuture(戻り値)を別のプログラムで使用するために、thenメソッドを使用しています。また、greeting関数で取得したfutureに「value」と適当な名前をつけ、コールバック関数の引数に代入し、コールバック関数内で使用しています。

参考

よかったらシェアしてね!
目次
閉じる