241

I like to simulate an asynchronous web service call in my Dart application for testing. To simulate the randomness of these mock calls responding (possibly out of order) I'd like to program my mocks to wait (sleep) for a certain period of time before returning the 'Future'.

How can I do this?

Vinnie
  • 12,400
  • 15
  • 59
  • 80

11 Answers11

330

2019 edition:

In Async Code

await Future.delayed(Duration(seconds: 1));

In Sync Code

import 'dart:io';

sleep(Duration(seconds:1));

Note: This blocks the entire process (isolate), so other async functions will not be processed. It's also not available on the web because Javascript is really async-only.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 1
    What is the difference btw the two of them (sleep vs Future.delayed)? What's going on behind the scenes in both scenarios? – Tomas Baran Jun 04 '20 at 21:01
  • 12
    `sleep()` completely blocks the entire isolate. No Dart code will run at all while it is sleeping. It probably compiles to something like C++'s `std::this_thread::sleep_for`. `Future.delayed()` schedules the async function to resume later, but then it returns control to the Dart event loop so that other async functions can continue to run. – Timmmm Jun 05 '20 at 12:47
  • For newer Dart/Flutter versions you should use const Duration(...). – maxmitz Oct 31 '22 at 17:04
165

You can also use the Future.delayed factory to complete a future after a delay. Here is an example of two functions that return a string asynchronously after a delay:

import 'dart:async';

Future sleep1() {
  return new Future.delayed(const Duration(seconds: 1), () => "1");
}

Future sleep2() {
  return new Future.delayed(const Duration(seconds: 2), () => "2");
}
Shailen Tuli
  • 13,815
  • 5
  • 40
  • 51
80

It's not always what you want (sometimes you want Future.delayed), but if you really want to sleep in your Dart command-line app, you can use dart:io's sleep():

import 'dart:io';

main() {
  sleep(const Duration(seconds:1));
}
Seth Ladd
  • 112,095
  • 66
  • 196
  • 279
33

I found that there are several implementations in Dart to make the code delay execution:

new Future.delayed(const Duration(seconds: 1)); //recommend

new Timer(const Duration(seconds: 1), ()=>print("1 second later."));

sleep(const Duration(seconds: 1)); //import 'dart:io';

new Stream.periodic(const Duration(seconds: 1), (_) => print("1 second later.")).first.then((_)=>print("Also 1 second later."));
//new Stream.periodic(const Duration(seconds: 1)).first.then((_)=>print("Also 1 second later."));
SpkingR
  • 965
  • 7
  • 14
22

For Dart 2+ syntax , in a async function context:

import 'package:meta/meta.dart'; //for @required annotation

void main() async {
  void justWait({@required int numberOfSeconds}) async {
    await Future.delayed(Duration(seconds: numberOfSeconds));
  }

  await justWait(numberOfSeconds: 5);
} 
Bono Lv
  • 577
  • 5
  • 7
7

This a useful mock that can take an optional parameter to mock an error:

  Future _mockService([dynamic error]) {
    return new Future.delayed(const Duration(seconds: 2), () {
      if (error != null) {
        throw error;
      }
    });
  }

You can use it like this:

  await _mockService(new Exception('network error'));
Jannie Theunissen
  • 28,256
  • 21
  • 100
  • 127
7

Dart runs all your code within a single process or thread, the event loop. Therefore also code within async blocks/methods, is, in reality, run within a "global" sequence of some sort and order that feeds the event loop. To say the same with other words: There is no, but one single "thread" in Dart (excluding Isolates for the moment, see below).

When having to mimic data, arriving over time, e.g. through streams, one might run into the pitfall of using sleep within code that runs in async blocks/methods. Thinking: "My code fires off a new thread and moves on happily and stays responsive on the UI layer and all!". But this is not the case: In Dart, you just shot yourself it the knee.

When using sleep anywhere, not just within async code, this will stop the "one and only" event loop and every "thread" is blocked, that is, all code, everything... (...as there are actually no "threads" like e.g. in Java).

Note: Also and foremost, the UI will block, not repaint, and not be responsive to any input. All the events that occured behind the scenes during sleep, will only become visible, after "wake up".

As an example, think of a list that appends items to itself (possibly through a stream / StreamBuilder). In "real app life", the data usually comes from an "outside source", that sends data in a delayed, unpredictable fashion. So, all is well...

...But when the data is mimicked from within your code, like by a button event, involving sleep, with sync or async, doesn't matter, the list will only be repainted at the very end, when all the sleeping has ended. Also any other button events for example, will also not be dispatched by the event loop until after that.

Consider this code:

DON'T

Future<VoidCallback?> asyncWithSleep() async {
  print('start');
  for (var i = 0; i < 5; i++) {
    sleep(const Duration(seconds: 1));
    print(i);
  }
  print('end');
  return null;
}

Prints:

flutter: start
flutter: 0
flutter: 1
flutter: 2
flutter: end

If you expected end would print before the numbers, then say it aloud now: "sleep in Dart causes all threads to wait". Basically, unless you are running a command-line script from top to bottom, or code within an isolate, forget about sleep.

To e.g. mimic data arriving from some source like a webservice, a database, or from the underlying platform, you could spawn a Future.delayed for each piece of data, you want to mock.

DO

void syncWithDelayedFutureAndNoSyncDownTheLine() { // doesn't have to be async but could, if Future setup takes too long
  print('start');
  for (var i = 0; i < 3; i++) {
    Future.delayed(const Duration(seconds: i + 1), () {
      print(i);
    });
  }
  print('end');
  return null;
}

This will neither block the UI nor anything else. It sets up three blocks of code that is asyncronosouly run in the future, here within 1, 2, and 3 seconds respectively to the for loop.

Prints:

flutter: start
flutter: end
flutter: 0
flutter: 1
flutter: 2

(If data mimicking every second seems too boring, add a bit of wiggle and randomness into the Duration argument of the Future.delayedparameter...)

The key to creating future events for simulations or tests, is to set the Duration time of the Future right. Blocking within the async code does not work as intended, as it blocks all.

If you still think you need to use sleep anywhere in your program, have a look at Dart's Isolates. I haven't used them yet but from what I can see, they look a bit like e.g. Java threads to me, without the burden of shared memory and it's many pitfalls. However, they are intended as "background workers", for compute/time intesive processing that could make the rest of the program sluggish, when run from the same main(), that is to say, within the same, the main isolate.

raoulsson
  • 14,978
  • 11
  • 44
  • 68
6

Since the edit que for the top answer is full, here the newest working adaptation of the issue:

In Async code:

await Future<void>.delayed(const Duration(seconds: 1));

in Sync code:

import 'dart:io';
sleep(const Duration(minutes: 1));

Note: This blocks the entire process (isolate), so other async functions will not be processed. It's also not available on the web because Javascript is really async-only.

Maritn Ge
  • 997
  • 8
  • 35
3

If you need to execute some code after a while

        Future.delayed(const Duration(seconds: 5), () {
//do something
        });
2

You Can use Like this: enter image description here

sleep(Duration(seconds: 5));

Or

  Future.delayed(const Duration(seconds: 5));
lava
  • 6,020
  • 2
  • 31
  • 28
0

Timer Class

Timer(Duration(seconds: 2), () {
// code here
});

After 2 seconds of sleep, code will be executed.

Source: Flutter Sleep