initialize static method
Create a DownloadProcess instance.
Note
- We do this in a static method as constructors can't be async.
Implementation
static Future<DownloadProcess> initialize() async {
// Completer as lock to ensure that the spawned Isolate's SendPort is not used before it's
// exchanged with the main Isolate.
//
// NOTE: (ReceivePort, SendPort) is a `Record` type, you might want to look it up on dart.dev.
//
// NOTE: A Completer is a Future that can be completed manually, this is important when you
// consider the async priority order in Dart as follows:
//
// 1. Sync Task > Synchronous code, executes first
//
// 2. Micro Task > high priority async code, executes after sync code
// usually for things like updating app state, created via
// `ScheduleMicrotask` / `Completer` / etc.
//
// 3. Macro Task / Event Loop Task > low priority async code, executes after microtasks
// usually for things like I/O & http requests, created via
// `Future` / `Stream` / etc.
//
// NOTE: A Completer.sync() is essentially a task that is sent to the top of the microtask
// queue, a.k.a an async task executed as soon as possible (potentially even synchronously).
// We use this here to minimize Isolate initialization time.
final connectionLock = Completer<(ReceivePort, SendPort)>.sync();
// Create a RawReceivePort (as we can set a different handler when we convert it to a
// ReceivePort later) and add in the connectionLock logic.
final initializationPort = RawReceivePort();
initializationPort.handler = (toSpawnedIsolatePort) {
connectionLock.complete(
(
ReceivePort.fromRawReceivePort(initializationPort),
toSpawnedIsolatePort as SendPort,
),
);
};
// Spawn worker Isolate, on literally any error close the initializationPort and rethrow.
try {
var _ = await Isolate.spawn(_isolateSetup, initializationPort.sendPort);
} on Object {
initializationPort.close();
rethrow;
}
// Wait for the connectionLock to complete, then return the ReceivePort and SendPort.
final (ReceivePort fromIsolatePort, SendPort toIsolatePort) = await connectionLock.future;
// Create a Downloader instance and return it.
return DownloadProcess._(toIsolatePort, fromIsolatePort);
}