javascript Essay -- timer cleanup final

Problem background

Product Manager: implement a list (including personnel name, online status and other fields), and update the online status field in the list every 10 seconds.
Development SE: the background push is complex, the project requires emergency launch, and the foreground timer query scheme is temporarily adopted.
Development and Implementation: the list query page (personList.vue) calls the list query interface (/ querylissapi). After the foreground query is successful, if it is judged that there is data, start the setTimeout query list interface for 10 seconds to update the list status data.

The specific codes are as follows:

<script>
// The project is based on the Vue framework
export default {
  data() {
    return {
      personList: [],
      timer: null
    }
  },
  created() {
    this.queryList()
  },
  beforeDestory() {
    this.clearQueryListTimer()
  },
  methods: {
    queryList() {
      axios.get('/queryListApi').then(data => {
        if (data && data.length) {
          this.personList = [...data]
          this.clearQueryListTimer()
          this.timer = setTimeout(() => {
            this.queryList()
          }, 10000)
        }
      })
    },
    clearQueryListTimer() {
      this.timer && clearTimeout(this.timer)
      this.timer = null
    }
  }
}
</script>

Problems found in development self-test:

  1. When the current page interface requests pending, switch the route to other pages, and the timer in the callback will still execute;
  2. Quickly switch between the current page and other pages, the timer runs multiple times, and the interface is called frequently and many times;
  3. Page jam, memory leak;

problem analysis

  1. When the interface is in pending status, switch the route, trigger beforedestination, clear timeout is cleared early, and the timer will still be started after the interface request is successful;
  2. Violent route switching should be avoided and anti shake operation should be added;
  3. From the results, the timer has a leak cleaning problem, resulting in memory leakage. The root cause of the problem points to this.timer;
  4. The this.timer variable will be modified every 10 seconds, and the point of this.timer cleaned by clearTimeout is unclear;

Solution

  1. In the timer callback, get the current page route and judge whether it is a personList.vue page. If not, clear the timer;
  2. Add anti shake operation for route switching and add global loading effect when interface requests;
  3. Save this.timer into an array timerArr and timerArr into session;
    During cleaning, take out timerArr in the session, traverse timerArr, and trigger clearTimeout;

The specific codes are as follows:

<script>
// The project is based on the Vue framework
export default {
  data() {
    return {
      personList: [],
      timer: null,
      loading: false
    }
  },
  created() {
    console.log(this.$route.path)
    this.queryList()
  },
  beforeDestory() {
    this.clearQueryListTimer()
  },
  methods: {
    queryList() {
      // loading effect adding
      this.loading = true
      axios.get('/queryListApi').then(data => {
        this.loading = false
        if (data && data.length) {
          this.personList = [...data]
          this.clearQueryListTimer()
          this.timer = setTimeout(() => {
            // Add routing judgment
            if (this.$route.path !== '/personList') {
              this.clearQueryListTimer()
              return
            }
            this.queryList()
          }, 10000)
          this.updateTimerArr(this.timer)
        }
      })
    },
    updateTimerArr(id) {
      let timerArr = JSON.parse(sessionStorage.getItem('timerArr') || '[]')
      timerArr.push(id)
      sessionStorage.setItem('timerArr', JSON.stringify(timerArr))
    },
    clearQueryListTimer() {
      let timerArr = JSON.parse(sessionStorage.getItem('timerArr') || '[]')
      if (timerArr.length) {
        for (let i = 0; i < timerArr.length; i++) {
          clearTimeout(timerArr[i])
        }
        sessionStorage.setItem('timerArr', '[]')
      }
    }
  }
}
</script>

Timer cleanup summary

  1. Do not use the timer if you can't use the timer in the project. When it is unavoidable, you must clean the timer;
  2. When meeting the needs of task status update and progress bar development, websocket is adopted. The background push and foreground update are the best, and the foreground polling is avoided;
  3. For simple timer requirements such as rotation chart, you can clean up the timer in the page life cycle;
  4. Interface pending causes the beforedestination life cycle to be bypassed, and timer cleaning can be used together with routing judgment;
  5. For complex scenarios (circular micro task interface query, etc.), assemble the open timer timer into an array, store it in the session or global variable, and cycle through the cleaning;
  6. If the writing of many timers in the old project is not standard, the temporary avoidance scheme is as follows:
    // Violent cleanup global timer
    let timer = setInterval(() => {}, 1000);
    for (let i = 0; i < timer + 1; i++) {
        clearInterval(i);
    }
    let timer2 = setTimeout(() => {}, 1000);
    for (let j = 0; j < timer2 + 1; j++) {
        clearTimeout(j);
    }
    

Tags: Javascript

Posted on Sun, 12 Sep 2021 23:05:07 -0400 by Markx