preface

In our daily development, we sometimes encounter some business functions that require users to do a waiting action and fail to obtain a real waiting time. At this time, we will need to simulate a real progress bar in order to improve the user’s sense of interactive experience, so that users will wait forever.

  • Knowing that we need to simulate a real progress bar, we started a simple analysis of the function of this virtual progress:
  1. Accept the default time range for virtual progress.
  2. Trigger function to start and end loading.
  3. Callbacks to load status, such as whether the load is OK or not, current percentage updates.
  4. Dynamic setTimeout execution time.
  5. Whether the load is complete (BL).
  6. Total time of false progress.
  7. The remaining half time of the total time of false progress.
  8. The current calculation of a progress.
  9. Does not associate with any framework technology (Vue, React), but can be used quickly by any framework.

Start putting up a shelf

Step 1: Accepted parameter type definition: here we accept the default time and 2 callbacks that can be used by the outside world.

interface FakeLoadingParamsType { initTime? : number setLoading? :(_bl: boolean) = > voidsetSchedule? :(_num: number) = > void
}
   
Copy the code

Step 2: Build the basic structure of our Class and declare the action behavior

interface FakeLoadingParamsType { initTime? : number setLoading? :(_bl: boolean) = > voidsetSchedule? :(_num: number) = > void
}

class FakeLoading {
    private initTime = 5; // Initialization time (the real time is initTime - initTime * 2)
    private isOK = false; / / is ok
    private timeOut = 0; // Loop time
    private num = 0; // False schedule time
    private half = 0; // Half the remaining progress
    private count = 0; // Progress
    private _setLoading(_bl: boolean){}// callback - whether it is currently being loaded
    private _setSchedule(_num? : number){}// callback - percentage of current progress
    constructor(props: FakeLoadingParamsType) {
        // 1. Accept the world as defined by the outside world - override the default time
        // 2. Accept the callback function passed in to our internal function
    }
    /** * start action */
    public begin = () = > {
        1. Initialize data
        // 2. Trigger the callback
        // 3
    }
    /** * End action */
    public over = () = > {
        // 1. Force a status update and trigger a callback
    }
    /** * Computes the rate at which progress is increased (doubles) */
    private computedSpeed(){}/** * Self-call delay increases progress */
    private circulationSubCount() {
        // 1. setTimeout is automatically invoked based on the defined time
        // 2. Calculate current progress - change the trigger time computedSpeed every time it exceeds half
        // 3. Judge whether the critical value (99) has been reached, forcing the correction is not increasing
        // 4. Calculate the current progress percentage value
        // 5. Self-call}}Copy the code

Step 3: Accept parameters and initialize – code

   constructor(props? : FakeLoadingParamsType) {
        // 1. Accept the world as defined by the outside world - override the default time
        this.initTime = props? .initTime ||this.initTime;
        // 2. Accept the callback function passed in to our internal function
        this._setLoading = (bl: boolean) = >{ props? .setLoading? .(bl); };this._setSchedule = (num: number) = >{ props? .setSchedule? .(num); }; }Copy the code

Step 4: Start and finish actions – code

    public begin = () = > {
        1. Initialize data
        this.num = parseInt(this.initTime * Math.random() + "") + this.initTime;
        this.half = this.num / 2;
        this.count = 0;
        this.timeOut = 200;
        this.isOK = false;
        // 2. Trigger the callback
        this._setSchedule(0);
        this._setLoading(true);
        // 3
        this.circulationSubCount();
    }
Copy the code
 public over = () = > {
        // 1. Force a status update and trigger a callback
        this.isOK = true;
        this._setSchedule(100);
        setTimeout(() = > {
            this._setLoading(false);
        }, 200);
    }
Copy the code

Step 5: Implementation of the self-calling loop function – code

 private circulationSubCount() {
        // 1. setTimeout is automatically invoked based on the defined time
        setTimeout(() = > {
            if (this.isOK) {
                return;
            }
            // 2. Calculate current progress - change the trigger time computedSpeed every time it exceeds half
            this.computedSpeed();
            this.count += 0.1;
            // 3. Judge whether the critical value (99) has been reached, forcing the correction is not increasing
            if (this.count >= this.num) {
                this._setSchedule(99);
            } else {
                // 4. Calculate the current progress percentage value
                this._setSchedule((this.count / this.num) * 100);
            }
            // 5. Self-call

            this.circulationSubCount();
        }, this.timeOut);
    }
Copy the code

Step 6: Calculate the rate of increase in progress (double) – code

This step is a simple simulation of a slower loading progress bar, for example:

The total progress is 100 percent, I am now loading at 50 percent, and my current loading state is more than half of my total time, so I will double the setTimeout callback time and recalcitate the remaining half time (from 50, 25, 12.5…). .

    private computedSpeed() {
        if (this.count >= this.half) {
            this.timeOut = this.timeOut * 2;
            this.half += this.half / 2; }}Copy the code

Try using:

function setSchedule(num: number) {
    console.log(num);
}
function setLoading(bl: boolean) {
    console.log(bl);
}
const fakeLoading = new FakeLoading({
    setSchedule, setLoading
})
fakeLoading.begin()
Copy the code

Output:

We’ll see that we’re starting to execute the code as expected, and it’s not increasing 99% of the time.

Service Usage – Use React as an example:

Used in custom hooks.

  1. Acceptable lifecycle callbacks
  2. Can update the UI
  3. Current schedule and loading state are exposed
  • Custom Hook implementation – Demo (this is the simplest example) :
import { useEffect, useRef, useState } from "react";
import FakeLoading from "./FakeLoading";
export const useLoading = (params) = > {
    const { beginCallBack, overCallBack } = params || {};
    const [schedule, setSchedule] = useState<number>(0);
    const [loading, setLoading] = useState(false);
    const LoadingObj = useRef({});
    useEffect(() = > {
        LoadingObj.current = newFakeLoading({ setSchedule, setLoading, }); } []);return {
        begin: () = >{ beginCallBack? . (); LoadingObj.current? .begin? . (); },over: () = >{ LoadingObj.current? .over? . (); overCallBack? . (); }, loading, setLoading,schedule: parseInt(schedule + ""),}; };Copy the code
  • UI layer using custom hook-demo:
      const { begin, over, schedule, loading } = useLoading({
         // Virtual progress class life cycle, not pass
        beginCallBack: () = > {
            // Business code
        },
        overCallBack: () = > {
           // Business code}});Copy the code
  • The same is true for other applications such as Redux, DVA, Mobx, vuE-x.

Complete code:

exportinterface FakeLoadingParamsType { initTime? : number; setLoading? :(_bl: boolean) = > void; setSchedule? :(_num: number) = > void;
}

export class FakeLoading {
    private initTime = 5; // Initialization time (the real time is initTime - initTime * 2)
    private isOK = false; / / is ok
    private timeOut = 0; // Loop time
    private num = 0; // False schedule time
    private half = 0; // Half the remaining progress
    private count = 0; // Progress
    private _setLoading(_bl: boolean){}// callback - whether it is currently being loaded
    private _setSchedule(_num? : number){}// callback - percentage of current progress
    constructor(props? : FakeLoadingParamsType) {
        // 1. Accept the world as defined by the outside world - override the default time
        this.initTime = props? .initTime ||this.initTime;
        // 2. Accept the callback function passed in to our internal function
        this._setLoading = (bl: boolean) = >{ props? .setLoading? .(bl); };this._setSchedule = (num: number) = >{ props? .setSchedule? .(num); }; }/** * start action */
    public begin = () = > {
        1. Initialize data
        this.num = parseInt(this.initTime * Math.random() + "") + this.initTime;
        this.half = this.num / 2;
        this.count = 0;
        this.timeOut = 200;
        this.isOK = false;
        // 2. Trigger the callback
        this._setSchedule(0);
        this._setLoading(true);
        // 3
        this.circulationSubCount();
    }
    /** * End action */
    public over = () = > {
        // 1. Force a status update and trigger a callback
        this.isOK = true;
        this._setSchedule(100);
        setTimeout(() = > {
            this._setLoading(false);
        }, 200);
    }
    /** * Computes the rate at which progress is increased (doubles) */
    private computedSpeed() {
        if (this.count >= this.half) {
            this.timeOut = this.timeOut * 2;
            this.half += this.half / 2; }}/** * Self-call delay increases progress */
    private circulationSubCount() {
        // 1. setTimeout is automatically invoked based on the defined time
        setTimeout(() = > {
            if (this.isOK) {
                return;
            }
            // 2. Calculate current progress - change the trigger time computedSpeed every time it exceeds half
            this.computedSpeed();
            this.count += 0.1;
            // 3. Judge whether the critical value (99) has been reached, forcing the correction is not increasing
            if (this.count >= this.num) {
                this._setSchedule(99);
            } else {
                // 4. Calculate the current progress percentage value
                this._setSchedule((this.count / this.num) * 100);
            }
            // 5. Self-call
            this.circulationSubCount();
        }, this.timeOut); }}Copy the code

conclusion

We can implement a virtual progress function with the simplest class, but extend it further, allowing for highly customized pause, reload, and true/false mixing. Interested partners can explore by themselves!

Finally, if this article is helpful to you, please click 👍. Thank you!!!!!