一、案例效果
使得数据实时变化,可以随时暂停和播放
二、代码案例
html
<button id="button">暂停</button>
js
let timerId = 1 // 模拟计时器id,唯一性let timerObj = {} // 计时器存储器function getData() {return new Promise((resolve,reject) => {setTimeout(() => {resolve({data:666})},500)})}// 轮询function start () {const id = timerId++timerObj[id] = trueconsole.log("start---",timerObj)async function timerFn () {console.log("start-111111--",timerObj[id])if (!timerObj[id]) return // 点击暂停需要退出const { data } = await getData() // 模拟请求console.log('轮询结果 ',data)setTimeout(timerFn, 1000)}timerFn()}// 暂停function stop () {timerObj = {}}start ()const botton = document.querySelector("#button")let isPlay = truebotton.addEventListener("click", function(){isPlay = !isPlaybotton.innerHTML = isPlay ? '暂停' : '播放'isPlay ? start() : stop()}, false)
三、控制台打印
四、分析过程
一进去页面执行start(),start是一个async函数,使得里面的异步也会像同步一样执行,函数的末尾timerId = setTimeout(start, 1000),1000毫秒后再次执行start(),形成了一个轮询(这里的每一个请求之间的间隔肯定是大于1000+500的,至于为什么,可以去了解一下浏览器异步执行原理)
将setTimeout的id赋值给timerId,点击按钮后,清除当前定时器
五、开发中出现得问题
- 假如没有const { data } = await getData()这步,点击的时候,click的回调函数能够执行,说明当前js肯定处于空闲状态(
js是单线程的
),这时的setTimeout(start, 1000)一定处于异步状态(js一次只有执行一个任务), - clearTimeout(timerId)可以很轻松的清除这次任务,不会让它进入js执行线程中执行
- 加上const { data } = await getData()之后,如果js现在处于setTimeout的回调函数已经执行并且等待await getData()中,js是空闲的,click可以执行,click清除了setTimeout的回调函数的执行(回调函数已经执行了),没有清除await getData()回调函数的执行,代码会继续执行console.log(data);timerId = setTimeout(start, 1000),从而不能停止循环,这就是bug产生的原因