You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter/Dart中如何实现函数执行完成后再周期性调用(避免并行)

Hey there! I totally get this frustration—Timer.periodic is great for simple periodic tasks, but it falls apart when your task takes longer than the interval, leading to parallel execution and those annoying variable race conditions. Streams are perfect for fixing this, and I’ll walk you through exactly how to implement what you need:

The Core Idea

Instead of triggering the task on a fixed timer regardless of completion, we want to run the task, wait 5 seconds after it finishes, then run it again. This ensures no parallel instances ever exist, and the minimum interval between task starts is always at least 5 seconds (plus whatever time the task itself takes).

Stream-Based Implementation

We can create a custom async stream that handles this sequential, delayed execution:

import 'dart:async';

// Define your interval as before
const markerRefreshInterval = Duration(seconds: 5);

// Create a stream that runs fetchMarkers sequentially with post-execution delay
Stream<void> markerRefreshStream() async* {
  while (true) {
    try {
      print('Starting marker fetch...');
      await _fetchMarkersFromDb(); // Wait for the task to complete fully
      print('Marker fetch completed successfully');
    } catch (e, stackTrace) {
      // Handle errors without breaking the stream
      print('Error fetching markers: $e\nStack trace: $stackTrace');
    }
    
    // Wait 5 seconds AFTER the task finishes before the next run
    print('Waiting 5 seconds before next fetch...');
    await Future.delayed(markerRefreshInterval);
  }
}

// To start the stream (e.g., in initState)
late StreamSubscription _refreshSubscription;

@override
void initState() {
  super.initState();
  _refreshSubscription = markerRefreshStream().listen((_) {});
}

// Don't forget to cancel the subscription to avoid memory leaks!
@override
void dispose() {
  _refreshSubscription.cancel();
  super.dispose();
}

Why This Works

  • No Parallel Execution: The await _fetchMarkersFromDb() ensures we never start a new instance until the previous one has fully completed.
  • Guaranteed Minimum Interval: The Future.delayed runs only after the task finishes, so the next task starts exactly 5 seconds after the last one ended.
  • Error Resilience: The try/catch block ensures a single failed fetch won’t stop the entire periodic process—your app will just log the error and keep going.

Why Timer.periodic Failed

Timer.periodic schedules a new callback every 5 seconds regardless of whether the previous callback finished. If _fetchMarkersFromDb() takes 6 seconds, you’ll end up with two instances running at the same time, causing race conditions on your incrementing variables. This stream approach eliminates that entirely.

内容的提问来源于stack exchange,提问作者Urmil Shroff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:53:00