setInterval
setInterval(f,time,arg1,arg2,....)
Arguments Interpret:
f: 目标执行函数
time: 每隔一段时间就执行函数f,可以执行无数次。指定的时间是“开始执行”的时间间隔。例如time=100ms 函数f执行完毕需要5ms,那么再过95ms而不是100ms函数f就会开始执行。
args: 传入函数f的参数
characteristic:
setInterval异步地将函数f加入任务队列。
risk points:
- 函数f在全局环境执行,这可能不同于函数定义时的上下文环境。采用self=this闭包或在函数f内部执行目标函数的方式可以确保函数中的变量始终处于函数定义时的上下文环境。
- setInterval具有阻塞-累积-释放效应。对阻塞-累积-释放效应的解释如下:setInterval设当前时刻为t,time=100ms,setInterval会生成一个开始执行的时刻对照表[t,t+100ms,t+200ms,t+300ms,....],后续按照该对照表标定的时间开始执行函数f,当在执行某一次函数f的过程中函数f被阻塞,造成后续函数f的执行时刻超过对照表所设定的时间,这些函数将被累积起来,累积的函数f的执行间隔将被设置为0,直到之后的函数f的开始执行时间与对照表能够正确对应。
setTimeout
setTimeout(f,time,arg1,arg2)
Arguments Interpret:
f: 目标执行函数
time: 间隔时间time后,执行目标函数f一次
args: 传入目标执行函数f的参数
risk points:
- 异步地将函数f的执行加入任务队列
- 默认仅执行一次
思考:如何设置从函数执行完毕后为基点,间隔时间time,并且能够执行无限次的定时器?
方案一: 通过执行次数i,增加每次setTimeout间隔的时间片长度。
for (let i = 0; i <= 5; i++) { setTimeout(() => console.log(`Hello #${i}`), 1000 * i) }
方案二: 通过自定义一个sleep函数,通过构建异步函数,在循环或递归中控制函数的执行间隔
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)) async function repeatGreetingsLoop() { for (let i = 0; i <= 5; i++) { await sleep(1000) console.log(`Hello #${i}`) } } repeatGreetingsLoop()
通过Promise对象设置自定义sleep函数的原理
new Promise(
(res,rej) => { // 操作函数
res('成功') // 修改promise对象的状态并传递对应的值
rej('失败')
}
)
当在操作函数中将res/rej传入定时器时, Promise对象在初始化过程中会保持pending状态,直到定时器生效,定时器中的res或rej操作完成时,Promise对象才会将状态修改为fulfilled或rejected。
sleep函数返回一个Promise对象,如果不加await关键字,Promise对象将是异步的,代码会同步下去,当1000ms后,Promise对象的状态改变为fulfilled,并传递Promise对象fulfilled时对应的结果;加上await关键字,程序将等待Promise对象 resolved之后,才会继续往下执行。从而实现sleep()函数的功能。
【理论上讲:只要创造一个对象或者过程,只要该对象或者过程的完全实现需要等待一定时间(例如,一个Promise对象需要经过setTimeout的时间才会执行resolve或者reject操作(兑现Promise)完成settled,最后得到Promise.Result异步返回值),就能够实现类似的sleep()函数。】
注意: await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。关于await与Promise的关系,可以参考:await与Promise
关于Promise类的细节,可以参考:Promise类的细节
关于类构造器、继承等细节,可以参考:类构造器、继承等细节
本文参考:参考地址
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。