zoukankan      html  css  js  c++  java
  • [RxJS] Loading Spinner with busyDelayMs & busyMinDurationMs api

    const { merge, timer, Subject, combineLatest } = require("rxjs");
    const {
      tap,
      mapTo,
      skip,
      filter,
      startWith,
      takeUntil,
      switchMap,
    } = require("rxjs/operators");
    
    const DELAY = 500;
    const MIN_DURATION = 1200;
    
    const taskStartSubject = new Subject();
    const taskStart = taskStartSubject.asObservable();
    const taskEndSubject = new Subject();
    const taskEnd = taskEndSubject.asObservable();
    const busyDelayTimer = timer(DELAY);
    const busyMinDurationTimer = timer(MIN_DURATION + DELAY);
    const busyDelayTimerStart = taskStart.pipe(switchMap(() => busyDelayTimer));
    const busyDelayTimerEnd = busyDelayTimerStart.pipe(takeUntil(taskEnd));
    const emitOnTaskEnd = taskEnd.pipe(mapTo(1));
    const emitOnDelayTimerEnd = busyDelayTimerEnd.pipe(mapTo(-1));
    const emitOnMinDurationEnd = busyMinDurationTimer.pipe(mapTo(-1));
    
    ////////////// start/////////////////
    
    const raceBetweenTaskAndDelay = combineLatest([
      emitOnTaskEnd.pipe(startWith(null)),
      emitOnDelayTimerEnd.pipe(startWith(null)),
    ]).pipe(skip(1));
    const taskEndBeforeDelay = raceBetweenTaskAndDelay.pipe(
      filter(([taskEndFirst, timerEndFirst]) => {
        return taskEndFirst === 1 && timerEndFirst === null;
      })
    );
    const shouldNotShowSpinner = taskEndBeforeDelay.pipe(mapTo(false));
    const taskEndAfterTimeout = raceBetweenTaskAndDelay.pipe(
      filter(([taskEndFirst, timerEndFirst]) => {
        return taskEndFirst === null && timerEndFirst === -1;
      })
    );
    const shouldShowSpinner = taskEndAfterTimeout.pipe(mapTo(true));
    const showSpinner = shouldShowSpinner.pipe(
      tap(() => {
        console.timeLog("spinner");
        console.log("show");
      })
    );
    
    /////////////// end ///////////////
    
    const raceBetweenTaskAndMinDuration = combineLatest([
      emitOnTaskEnd.pipe(startWith(null)),
      emitOnMinDurationEnd.pipe(startWith(null)),
    ]).pipe(skip(1));
    const hideSpinnerUntilMinDurationEnd = raceBetweenTaskAndMinDuration.pipe(
      filter(([taskEndFirst, timerEndFirst]) => {
        return taskEndFirst === 1 && timerEndFirst === null;
      })
    );
    const hideSpinnerAfterTimerAndTaskEnd = raceBetweenTaskAndMinDuration.pipe(
      filter(([taskEndFirst, timerEndFirst]) => {
        return taskEndFirst === 1 && timerEndFirst === -1;
      })
    );
    const hideSpinner = merge(
      // case 1: should not show spinner at all
      shouldNotShowSpinner,
      // case 2: task end, but wait until min duration timer ends
      combineLatest([hideSpinnerUntilMinDurationEnd, emitOnMinDurationEnd]),
      // case 3: task takes a long time, wait unitl its end
      hideSpinnerAfterTimerAndTaskEnd
    ).pipe(
      tap(() => {
        console.timeLog("spinner");
        console.log("hide");
      })
    );
    const Spinner = showSpinner.pipe(takeUntil(hideSpinner));
    
    // test
    Spinner.subscribe();
    
    console.log("task start");
    console.time("spinner");
    taskStartSubject.next();
    
    // Case 1: Should not show spinner
    
    setTimeout(() => {
      taskEndSubject.next();
    }, 50);
    
    // Case 2: Should show spinner when busyMinDurationMs end
    /*
    setTimeout(() => {
      taskEndSubject.next();
    }, 600);
    */
    // Case 3: Should show spinner until task ends
    /*
    setTimeout(() => {
      taskEndSubject.next();
    }, 2000);
    */
  • 相关阅读:
    左侧列固定的表格
    百度地图上添加多个标记,标记上添加信息展示窗口、跳转到导航界面
    vue-cli4版本解决eslint问题
    使用脚手架搭建项目
    正则表达式学习
    函数参数:
    装饰器(重点)
    列表生成式、生成器、迭代器
    logging 日志模块
    json 、 pickle 、shelve序列化
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12908045.html
Copyright © 2011-2022 走看看