JS中定時(shí)器的使用及頁(yè)面切換時(shí)定時(shí)器無(wú)法清除問(wèn)題的解決辦法
一、定時(shí)器的區(qū)別:
1、定時(shí)器分類(lèi):
JS有兩種定時(shí)器分別是setTimeout()和setInterval(),這兩個(gè)區(qū)別就是setTimeout()是一次性的定時(shí)器,而setInterval()是循環(huán)的定時(shí)器。
(1)setTimeout()
只執(zhí)行一次,在指定的毫秒數(shù)之后,就會(huì)立即停止
(2)setInterval()
不管語(yǔ)句是否執(zhí)行完成,不管是否執(zhí)行錯(cuò)誤,到下一次指定的毫秒數(shù)后就會(huì)立即執(zhí)行
(3)舉例:
比如想調(diào)用一個(gè)接口,需要1s定時(shí)刷新一次,但是接口2s才返回?cái)?shù)據(jù),使用setInterval()的話就會(huì)出現(xiàn)問(wèn)題,在上次接口還沒(méi)有返回結(jié)果的情況下,又重新調(diào)用了接口,這樣交互效果很不好,影響性能;所以在開(kāi)發(fā)中,在遇到接口需要定時(shí)的情況,我都會(huì)使用setTimeout(),配合clearTimeout使用,需要注意的是:a. 不能把setTimeout寫(xiě)成死循環(huán); b. 注意清除定時(shí)器的情況;c. 頁(yè)面切換清除定時(shí)器的情況,這個(gè)是重點(diǎn),也是下面需要講到的問(wèn)題
2、setInterval()的使用場(chǎng)景:
(1)可以使用在動(dòng)畫(huà)效果上,比如閃爍效果
(2)其他不需要異步及調(diào)用接口的方法 都可以使用(個(gè)人的總結(jié),可能不太對(duì))
(3)如果想停止,可以使用clearInterval()或關(guān)閉窗口
3、setTimeout()的使用場(chǎng)景
(1)定時(shí)器執(zhí)行一次的情況下 可以使用,這種場(chǎng)景很少見(jiàn),這里就不舉例了
(2)調(diào)用的接口需要定時(shí)查詢的情況,這種場(chǎng)景很常見(jiàn),比如天氣查詢,定時(shí)10秒刷新一次,在開(kāi)發(fā)中經(jīng)常用到
4、定時(shí)器遇到的問(wèn)題(以下是我在做項(xiàng)目中遇到的問(wèn)題及自己的一點(diǎn)想法)
(1)用setTimeout 實(shí)現(xiàn)定時(shí)查詢 一般用于執(zhí)行的方法中調(diào)用后臺(tái)接口的情況,等接口請(qǐng)求完后,再執(zhí)行下一次的接口調(diào)用; 使用setInterval的話,一般用于不調(diào)用后臺(tái)接口的情況
(2)要是用setInterval用來(lái)調(diào)用后端接口,可能會(huì)有問(wèn)題,比如定時(shí)2s刷新,接口可能會(huì)3s才返回接口,還沒(méi)等這次返回結(jié)果去刷新頁(yè)面,就又去重新查詢數(shù)據(jù)了,可能會(huì)造成數(shù)據(jù)混亂
(3)在使用setTimeout的時(shí)候,需要注意的問(wèn)題就是不要寫(xiě)成死循環(huán);再就是記得清除定時(shí)器,清除定時(shí)器用clearTimeout 方法
(4)在使用react的時(shí)候,會(huì)遇到路由切換的情況,有時(shí)候會(huì)出現(xiàn)定時(shí)器清除不掉的情況
比如在A頁(yè)面中是用了定時(shí)器setTimeout,但是沒(méi)有清除定時(shí)器,那么在訪問(wèn)B頁(yè)面的時(shí)候,A頁(yè)面的定時(shí)器還會(huì)執(zhí)行,請(qǐng)求的接口也仍然會(huì)繼續(xù)執(zhí)行,所以要清除一下,在A頁(yè)面切換到B頁(yè)面的時(shí)候,會(huì)執(zhí)行組件卸載的方法(componentWillUnmount),在該方法中調(diào)用清除定時(shí)器的方法(clearTimeout);
有時(shí)候可能會(huì)失敗,比如剛巧在執(zhí)行componentWillUnmount的時(shí)候,恰好代碼也執(zhí)行到定時(shí)器執(zhí)行的調(diào)用后臺(tái)接口的方法中了,還在請(qǐng)求接口,在請(qǐng)求成功到執(zhí)行下一次定時(shí)器的時(shí)候,恰好componentWillUnmount方法把之前的定時(shí)器清除了,這樣雖然清除了上次的定時(shí)器,但是那個(gè)方法中又再次使用了定時(shí)器,這樣的話,就會(huì)造成清不掉的問(wèn)題(這個(gè)大家可能會(huì)遇到這個(gè)問(wèn)題)
(5)上述問(wèn)題的React示例代碼及運(yùn)行截圖
測(cè)試頁(yè)面1的代碼:
import React, { Component } from 'react'; import { getRealtimeValueByCodeList } from '../../SVGManagementNew/services/index'; // 引用的查詢實(shí)時(shí)值的接口 export default class TestPage1 extends Component { constructor(props) { super(props); this.state = { refreshTime: 500 // 500毫秒 }; this.timeout = null; } componentDidMount() { this.getRealValueFn(); } componentWillUnmount() { clearTimeout(this.timeout); } // 獲取實(shí)時(shí)值 getRealValueFn = () => { getRealtimeValueByCodeList('CF159FCALT2DPU2A') .then((res) => { console.log(res); this.timeout = setTimeout(() => { console.log('page1定時(shí)查詢'); this.getRealValueFn(); }, this.state.refreshTime); }) .catch((e) => { console.log(e); }); }; render() { return <div>TestPage1</div>; } }
測(cè)試頁(yè)面2的代碼:
import React, { Component } from ‘react’;
import { getRealtimeValueByCodeList } from ‘…/…/SVGManagementNew/services/index’; // 引用的查詢實(shí)時(shí)值的接口
export default class TestPage2 extends Component { constructor(props) { super(props); this.state = { refreshTime: 500 // 500毫秒 }; this.timeout = null; } componentDidMount() { this.getRealValueFn(); } componentWillUnmount() { clearTimeout(this.timeout); } // 獲取實(shí)時(shí)值 getRealValueFn = () => { getRealtimeValueByCodeList('CF159FDRJ4_IDCS00116_R2') .then((res) => { console.log(res); this.timeout = setTimeout(() => { console.log('page2定時(shí)查詢'); this.getRealValueFn(); }, this.state.refreshTime); }) .catch((e) => { console.log(e); }); }; render() { return <div>TestPage1</div>; } }
測(cè)試頁(yè)面3的代碼
import React, { useState, useRef, useEffect } from ‘react’;
import PropTypes from ‘prop-types’;
import { getRealtimeValueByCodeList } from ‘…/…/SVGManagementNew/services/index’; // 引用的查詢實(shí)時(shí)值的接口
function TestPage3(props) { const [refreshTime, setRefreshTime] = useState(500); const timeout = useRef(); const getRealValueFn = () => { getRealtimeValueByCodeList('CF159FDDM1_TEST_CTM') .then((res) => { console.log(res); timeout.current = setTimeout(() => { console.log('page3定時(shí)查詢'); getRealValueFn(); }, refreshTime); }) .catch((e) => { console.log(e); }); }; useEffect(() => { getRealValueFn(); return () => { clearTimeout(timeout.current); }; }, []); return <div>TestPage3</div>; } TestPage3.propTypes = {}; export default TestPage3;
配置三個(gè)路由,然后來(lái)回切換這三個(gè)頁(yè)面,就會(huì)出現(xiàn)定時(shí)器清除不掉的情況,三個(gè)頁(yè)面的定時(shí)器就會(huì)一直在刷新,這樣就會(huì)造成資源上的浪費(fèi)及占用內(nèi)容,要是頁(yè)面很多、定時(shí)刷新的接口很多、接口很耗費(fèi)資源的話,那么這種情況就會(huì)影響整個(gè)程序的運(yùn)行,有可能還會(huì)引起系統(tǒng)崩潰
上圖就是我在來(lái)回切換三個(gè)測(cè)試頁(yè)面的時(shí)候,出現(xiàn)上述說(shuō)的問(wèn)題,可以自己把上述的代碼試驗(yàn)下
5、解決上述遇到的第四個(gè)問(wèn)題,即使用setTimeout頁(yè)面切換時(shí)定時(shí)器無(wú)法清除的問(wèn)題
a. 解決思路:
(1)從問(wèn)題的根本出發(fā),問(wèn)題的根本就是在頁(yè)面切換的時(shí)候,因?yàn)槎〞r(shí)器緩存的問(wèn)題,在切換到其他的頁(yè)面后,無(wú)法清除,還會(huì)繼續(xù)在緩存中繼續(xù)執(zhí)行;
(2)那么從這個(gè)思路上去想,在從A頁(yè)面(有定時(shí)器)跳轉(zhuǎn)到B頁(yè)面的時(shí)候,A頁(yè)面的定時(shí)器沒(méi)有清除掉,那么是否是可以在A頁(yè)面的定時(shí)器方法那定義個(gè)變量,然后在全局定義個(gè)變量,然后通過(guò)這兩個(gè)變量來(lái)判斷是否不執(zhí)行定時(shí)器呢;
(3)根據(jù)這個(gè)思路去想,那么是否可以根據(jù)路由去判斷,比如在訪問(wèn)到A頁(yè)面的時(shí)候,在A頁(yè)面的代碼中記錄下A頁(yè)面的路由到一個(gè)參數(shù)中(該參數(shù)在定時(shí)器執(zhí)行的時(shí)候,是一塊保存到緩存中的,在切換路由的時(shí)候,并不會(huì)清除,這個(gè)是一個(gè)存在緩存中的變量),然后在路由切換的時(shí)候,監(jiān)聽(tīng)路由的變化,記錄最新訪問(wèn)的路由,保存到window對(duì)象中(因?yàn)閣indow是全局的,在任何地方都可以使用);
(4)那么這兩個(gè)變量都有了,然后根據(jù)這兩個(gè)變量判斷,如果相等的話,那說(shuō)明正好是這個(gè)頁(yè)面,可以執(zhí)行定時(shí)器,如果不相等,那么當(dāng)前訪問(wèn)的頁(yè)面不是這個(gè)頁(yè)面,那么定時(shí)器就不執(zhí)行了
b. 實(shí)現(xiàn)步驟:
(1)在外部定義一個(gè)監(jiān)控方法,可以在main.js中 也可以在index.js中,也可以在路由切換中的文件中,把下面的代碼加入進(jìn)去,注意的是location的獲取,有的js文件中可能獲取不到
window.onhashchange = () => { console.log('監(jiān)聽(tīng)路由變化'); // 獲取當(dāng)前變化的路由 window.curPathName = this.props.location.pathname; };
下圖是我自己添加的位置:
(2)在使用定時(shí)器的文件中,設(shè)置每個(gè)文件使用時(shí)訪問(wèn)的路由地址
(3)判斷是否加載定時(shí)器
c.完整的示例代碼,可以正常清除定時(shí)器的
測(cè)試頁(yè)面1的代碼:
import React, { Component } from 'react'; import { getRealtimeValueByCodeList } from '../../SVGManagementNew/services/index'; // 引用的查詢實(shí)時(shí)值的接口 export default class TestPage1 extends Component { constructor(props) { super(props); this.state = { refreshTime: 500, // 500毫秒 curPageUrl: '' // 當(dāng)前頁(yè)面的訪問(wèn)地址 }; this.timeout = null; } componentDidMount() { const urlParams = window.location.href; this.setState({ curPageUrl: urlParams }); this.getRealValueFn(); } componentWillUnmount() { clearTimeout(this.timeout); } // 獲取實(shí)時(shí)值 getRealValueFn = () => { getRealtimeValueByCodeList('CF159FCALT2DPU2A') .then((res) => { console.log(res); if (this.state.curPageUrl.indexOf(window.curPathName) >= 0 || !window.curPathName) { this.timeout = setTimeout(() => { console.log('page1定時(shí)查詢'); this.getRealValueFn(); }, this.state.refreshTime); } }) .catch((e) => { console.log(e); }); }; render() { return <div>TestPage1</div>; } }
測(cè)試頁(yè)面2的代碼:
import React, { Component } from 'react'; import { getRealtimeValueByCodeList } from '../../SVGManagementNew/services/index'; // 引用的查詢實(shí)時(shí)值的接口 export default class TestPage2 extends Component { constructor(props) { super(props); this.state = { refreshTime: 500, // 500毫秒 curPageUrl: '' // 當(dāng)前頁(yè)面的訪問(wèn)地址 }; this.timeout = null; } componentDidMount() { const urlParams = window.location.href; this.setState({ curPageUrl: urlParams }); this.getRealValueFn(); } componentWillUnmount() { clearTimeout(this.timeout); } // 獲取實(shí)時(shí)值 getRealValueFn = () => { getRealtimeValueByCodeList('CF159FDRJ4_IDCS00116_R2') .then((res) => { console.log(res); if (this.state.curPageUrl.indexOf(window.curPathName) >= 0 || !window.curPathName) { this.timeout = setTimeout(() => { console.log('page2定時(shí)查詢'); this.getRealValueFn(); }, this.state.refreshTime); } }) .catch((e) => { console.log(e); }); }; render() { return <div>TestPage1</div>; } }
測(cè)試頁(yè)面3的代碼:
import React, { useState, useRef, useEffect } from 'react'; import PropTypes from 'prop-types'; import { getRealtimeValueByCodeList } from '../../SVGManagementNew/services/index'; // 引用的查詢實(shí)時(shí)值的接口 function TestPage3(props) { const [refreshTime, setRefreshTime] = useState(500); const [curPageUrl, setCurPageUrl] = useState(window.location.href); const timeout = useRef(); const getRealValueFn = () => { getRealtimeValueByCodeList('CF159FDDM1_TEST_CTM') .then((res) => { console.log(res); if (this.state.curPageUrl.indexOf(window.curPathName) >= 0 || !window.curPathName) { timeout.current = setTimeout(() => { console.log('page3定時(shí)查詢'); getRealValueFn(); }, refreshTime); } }) .catch((e) => { console.log(e); }); }; useEffect(() => { console.log(curPageUrl); getRealValueFn(); return () => { clearTimeout(timeout.current); }; }, []); return <div>TestPage3</div>; } TestPage3.propTypes = {}; export default TestPage3;
總結(jié):
到此這篇關(guān)于JS中定時(shí)器的使用及頁(yè)面切換時(shí)定時(shí)器無(wú)法清除問(wèn)題的解決辦法的文章就介紹到這了,更多相關(guān)JS定時(shí)器無(wú)法清除解決內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript獲取元素文本內(nèi)容的通用函數(shù)
獲取元素文本內(nèi)容的通用函數(shù),思路很好值得參考。2009-12-12使用Webpack壓縮與轉(zhuǎn)譯JavaScript代碼的操作方法
在Web開(kāi)發(fā)中,代碼的性能和加載時(shí)間是用戶體驗(yàn)的重要組成部分,為此,將JavaScript代碼壓縮和優(yōu)化是發(fā)布前一個(gè)必不可少的步驟,所以本文給大家介紹了如何使用Webpack壓縮與轉(zhuǎn)譯JavaScript代碼,需要的朋友可以參考下2024-05-05JS庫(kù)之Three.js 簡(jiǎn)易入門(mén)教程(詳解之一)
three.js是一款webGL框架,由于其易用性被廣泛應(yīng)用。下面腳本之家小編通過(guò)案例給大家闡述three.js的基本配置方法,具體內(nèi)容詳情大家參考下本文吧2017-09-09關(guān)于ckeditor在bootstrap中modal中彈框無(wú)法輸入的解決方法
今天小編就為大家分享一篇關(guān)于ckeditor在bootstrap中modal中彈框無(wú)法輸入的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09javascript根據(jù)時(shí)間生成m位隨機(jī)數(shù)最大13位
javascript根據(jù)時(shí)間生成m位隨機(jī)數(shù),最大13位隨機(jī)數(shù),并且不能保證首位不為0,實(shí)現(xiàn)代碼如下,需要的朋友可以參考下2014-10-10如何制作浮動(dòng)廣告 JavaScript制作浮動(dòng)廣告代碼
如果有一定的JavaScript基礎(chǔ),制作浮動(dòng)廣告還是比較容易的,利用閑暇時(shí)間簡(jiǎn)單制作了一個(gè),感興趣的朋友可以參考下哦2012-12-12