本篇主要内容: 异步, 定时器引发的思考
预计阅读时间: 8 分钟
了解
我们都知道在 JS 中定时器有两种 setInterval() , setTimeout() setInterval() : 按照指定的周期 (以毫秒计) 来调用函数或计算表达式. 方法会不停地调用函数, 直到 clearInterval() 被调用或窗口被关闭. setTimeout() : 在指定的毫秒数后调用函数或计算表达式.
那么问题来了, 定时器真的是定时执行的吗? 刚开始我认为定时器肯定是定时执行的啊, 要不然怎么会叫做定时器呢, 后来我感觉我好像错了, 所以今天就来说说这个问题 定时器真的是定时执行的吗
测试
- var start = Date.now()
- console.log('启动定时器前...')
- setTimeout(function () {
- console.log('定时器执行了:', Date.now()-start)
- }, 100)
- console.log('启动定时器后...');
我们会发现定时器执行了 101ms, 一般会延迟一丁点(可以接受), 说白了就是准确的, 如果说 300ms 之后执行呢?
- var start = Date.now()
- console.log('启动定时器前...')
- setTimeout(function () {
- console.log('定时器执行了:', Date.now()-start)
- }, 100)
- console.log('启动定时器后...');
- for (var i = 0; i < 1000000000; i++) {
- }
如果像上边这种情况, 本来是 200ms, 但是现在变成了 1941ms, 那还合适吗?
也就是说我们的定时器真的能保证定时吗?
答案是不能, 也可能延迟执行, 是在原有设定的时间上又有延迟, 加入本来是 200ms, 那么现在是 1941ms, 所以说定时器并不能真正保证定时执行
注意: 定时器的回调函数是在主线程执行, 无论是非回调函数还是回调函数都是在主线程执行
JS 执行方式
这时候就说到了一个概念 --- JS 是单线程执行的
那如何证明 JS 执行是单线程的呢? 尤其是一些回调函数中, 我们把握不住是主线程执行还是分线程执行的, 所以我们现在就验证下 JS 是单线程执行的
- setTimeout(function () {
- console.log('timeout 2')
- }, 2000)
- setTimeout(function () {
- console.log('timeout 1')
- }, 1000)
- function fn () {
- console.log('fn()');
- }
- fn()
- console.log('alert 之前')
- alert('提示...')
- console.log('alert 之后')
执行流程: fn() alert 之前 弹窗
当我点击确认后, timeout 2 和 timeout 1 是立即执行还是过一会执行
alert 之后 timeout 1 timeout 2
我们发现是过一会执行, 所以说 alert() 的作用是暂停当前主线程, 同时暂停计时. 点击确认后, 回复程序执行和计时
小结
如何证明 JS 执行是单线程的?
setTimeout() 的回调函数是在主线程执行的
定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
- setTimeout(function () {
- alert('2222222')
- console.log('timeout 2')
- }, 2000)
- setTimeout(function () {
- alert('1111111')
- console.log('timeout 1')
- }, 1000)
- function fn () {
- console.log('fn()');
- }
- fn()
- console.log('alert 之前')
- alert('提示...')
- console.log('alert 之后')
其实呢到现在咱们也不能清楚地看到 JS 是如何执行的, 要说到这个, 我们就得说下代码分类, 之前也写过代码分类, 全局代码和函数局部代码.
代码分类
这一次呢我们分为初始化代码和回调代码
回调代码就是回调函数中的代码
setTimeout 是本文的初始代码
接下来就是比较重要的一段函数了
- setTimeout(function () {
- console.log('timeout 0')
- }, 0)
- console.log('昼猫')
这一段代码中是谁先执行?
总结
JS 引擎执行代码的基本流程:
先执行初始化代码: 包含一些特别的代码, 例如: 设置定时器, 绑定事件监听, 发送 Ajax 请求
在后面在某个时刻才会执行回调代码
回调函数我们平常时候会说是异步执行
也就是说某些代码 (某些东西) 必须在所有的初始化代码执行后才有可能得到被执行, 这样的代码我们成为异步代码
来源: https://www.cnblogs.com/zhoumao/p/10098780.html