Skip to main content

Async Patterns Guide

How to use EFM's async functions for non-blocking file I/O.

Why Use Async?

Synchronous file operations block the game thread, causing frame hitches. Use async operations for:

  • Loading large files
  • Saving game state during gameplay
  • Downloading content from the web
  • Batch operations on many files

Async Read

Read as Bytes

AsyncReadFile(Self, FilePath, OnComplete)
OnComplete(bSuccess, Data):
if bSuccess:
ProcessBytes(Data)
else:
HandleError("Failed to read: " + FilePath)

Read as String

AsyncReadFileAsString(Self, FilePath, OnComplete)
OnComplete(bSuccess, Content):
if bSuccess:
ParseConfig(Content)
else:
LoadDefaultConfig()

Async Write

Write Bytes

AsyncWriteFile(Self, FilePath, ByteData, OnComplete)
OnComplete(bSuccess, WrittenPath):
if bSuccess:
Log("Saved to: " + WrittenPath)
else:
LogError("Failed to save")

Write String

AsyncWriteString(Self, FilePath, JsonString, OnComplete)
OnComplete(bSuccess, WrittenPath):
if bSuccess:
OnSaveComplete()
else:
OnSaveFailed()

Async Copy/Move

Copy

AsyncCopyFile(Self, SourcePath, DestPath, OnComplete)
OnComplete(bSuccess, Source, Destination):
if bSuccess:
Log("Copied: " + Source + " -> " + Destination)
else:
LogError("Copy failed")

Move

AsyncMoveFile(Self, SourcePath, DestPath, OnComplete)
OnComplete(bSuccess, Source, Destination):
if bSuccess:
Log("Moved: " + Source + " -> " + Destination)

Chaining Async Operations

Read, modify, and write back:

// Step 1: Read
AsyncReadFileAsString(Self, ConfigPath, OnReadComplete)
OnReadComplete(bSuccess, Content):
if not bSuccess:
Content = CreateDefaultConfig()

// Step 2: Modify
ModifiedContent = UpdateConfig(Content, NewValues)

// Step 3: Write
AsyncWriteString(Self, ConfigPath, ModifiedContent, OnWriteComplete)
OnWriteComplete(bSuccess2, WrittenPath):
if bSuccess2:
Log("Config saved")
else:
LogError("Failed to save config")

Download with Progress

DownloadFile(
Self,
"https://example.com/update.zip",
GetGameSavedDirectory() + "update.zip",
OnProgress(URL, ProgressPercent, BytesDownloaded):
// Update UI
ProgressBar.SetPercent(ProgressPercent / 100.0)
StatusText.SetText(
"Downloading: " + FormatBytes(BytesDownloaded)
),
OnComplete(bSuccess, URL, SavedPath):
if bSuccess:
StatusText.SetText("Download complete!")
InstallUpdate(SavedPath)
else:
StatusText.SetText("Download failed")
RetryButton.SetVisibility(Visible)
)

Batch Operations with Progress

BatchCopyFiles(
Self,
SourceFiles,
DestFiles,
OnProgress(CurrentIndex, TotalCount, CurrentFile, bSuccess):
Percent = (CurrentIndex + 1) / TotalCount * 100
ProgressBar.SetPercent(Percent / 100.0)
StatusText.SetText(
CurrentIndex + 1 + "/" + TotalCount + ": " + CurrentFile
),
OnComplete(bAllSuccess, SuccessCount, FailedCount):
if bAllSuccess:
StatusText.SetText("All " + SuccessCount + " files copied!")
else:
StatusText.SetText(
SuccessCount + " succeeded, " + FailedCount + " failed"
)
)

Best Practices

  1. Always handle the failure case - async operations can fail due to permissions, disk space, network issues
  2. Show progress to the user - use the progress callbacks for long operations
  3. Don't block waiting for async - use the callback pattern, not polling
  4. Cancel downloads when appropriate - use CancelDownload(URL) when the user navigates away
  5. Use async for save games - avoid frame hitches during gameplay