Throttling Events and Locking Methods

前端 未结 5 2034
小鲜肉
小鲜肉 2021-02-04 18:15

Let\'s pretend I have something like this:


And something like this:

publ         


        
5条回答
  •  执念已碎
    2021-02-04 18:38

    Here is what I have (the code is tested, btw). It is based on the event throttling extension I created a few years ago. I think a good name for it would be Ouroboros. The major thing about it is that opposite to when using Throttle, it starts the work immediately if a cooldown has passed.

    public static IObservable CombineVeryLatest(
        this IObservable leftSource,
        IObservable rightSource, 
        Func selector)
    {
        return Observable.Defer(() =>
        {
            int l = -1, r = -1;
            return Observable.CombineLatest(
                leftSource.Select(Tuple.Create),
                rightSource.Select(Tuple.Create),
                    (x, y) => new { x, y })
                .Where(t => t.x.Item2 != l && t.y.Item2 != r)
                .Do(t => { l = t.x.Item2; r = t.y.Item2; })
                .Select(t => selector(t.x.Item1, t.y.Item1));
        });
    }
    
    public static IObservable WorkSequencer(
        this IObservable source, Func> work)
    {
        return source.Publish(src =>
        {
            var fire = new Subject();
            var fireCompleted = fire.SelectMany(x => work()).Publish();
            fireCompleted.Connect();
            var whenCanFire = fireCompleted.StartWith(default(TWork));
    
            var subscription = src
                .CombineVeryLatest(whenCanFire, (x, flag) => x)
                .Subscribe(fire);
    
            return fireCompleted.Finally(subscription.Dispose);
        });
    }
    

    Then usage would be:

        private int _counter;
    
        public MainWindow()
        {
            InitializeComponent();
            var clicks = Observable
                .FromEventPattern(TestBn, "Click")
                .Do(_ =>
                {
                    Console.WriteLine("click");
                    _counter++;
                });
            clicks.WorkSequencer(DoWork).Subscribe();
        }
    
        private async Task DoWork()
        {
            var workNumber = _counter;
            Console.WriteLine("Work Start " + workNumber);
            await Task.WhenAll(Task.Delay(_counter*100), Task.Delay(1000));
            Console.WriteLine("Work Done " + workNumber);
            return _counter;
        }
    

提交回复
热议问题