JavaScript之setTimeout
JavaScript之setTimeout
由setTimeout
引发的一些了解 -> 事件循环机制、异步队列、时钟周期、执行上下文
js里常见的2个定时器:
setTimeout
和setInterval
,指定一定时间后触发其第一个参数函数(异步回调函数)然后执行函数体内的代码发生一些操作、变化….
e.g.1
1 | setTimeout(function(){console.log(4)},0); |
Pormise,
Promise
对象代表一个异步操作,它有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败),Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。
先看
1 | setTimeout(function () { |
在浏览器控制台可以看到好像确实是立马就输出123了。
先看下
1 | for (var i = 0; i < 1000; i++) { |
这个很好理解,常规思维都是顺序执行,这个结果也是如常规思维所想。
再看(改变下顺序):
1 | setTimeout(function () { |
在浏览器控制台执行,发现先输出的是for
循环内的内容,无论循环条件里是1000还是100 或是 10,都是先执行的循环体最后执行的setTimeout
分析:首先代码被JS解释引擎(如V8)顺序加载解释并执行,到遇到setTimeout
函数时,会将其第一个function参数函数放入异步队列排队等待线程空闲后再按照队列顺序执行。
new Promise
是第一个参数是一个同步函数,new Promise
最终返回的结果是一个promise
对象, .then()
方法也是异步的,所以代码执行到此处时会将.then()
的回调函数放入一个异步队列,当new Promise
返回的promise
达到fulfilled状态时且当前线程空闲时就会执行.then()
内的异步回调函数输出结果5, 再接着执行console.log(3);
控制台输出3。
最后当前JS线程已将代码遍历完并执行完,然后获取异步队列的内回调函数,这里关键在于:为什么先执行的是new Promise
返回的Promise
对象的.then()
里的方法而不是setTimeout
里的参数函数。因为浏览器或webview的时间钟,时间钟是由机器硬件的时间周期决定(CPU时钟周期)。
总结:js主线程在执行当前代码这个线程手里,当前线程只有空闲后,才回去处理事件队列,虽然setTimeout
设定的时间已到,但是也得等队列里所有代码已执行完毕,最后才处理setTimeout
里的东西。
1 | setTimeout("console.log('test!')", 1000); |
执行试试。必须要等待用户点击确认按钮后才会继续执行。
因为alert挂起了主线程,使得当前主线程被block(同样的函数还是prompt()
, confirm()
),主线程被挂起,整个当前执行js的进程进入等待状态,事件触发或代码执行都被中断,计时器也会暂停计时 ,当主线程恢复后,余下的代码继续执行,计时器安装时钟周期重新开始计时。
再看外国网站的例子[JakeArchibald.com]
e.g.2
1 | console.log('script start'); |
运行输出:
1 | script start |
Promise
对象经过resolve
后的.then
是异步的. 所以promise1 和 promise2的输出会在第3、4行输出;(setTimtout是因为 异步队列+系统时钟周期导致最后被执行–即当前线程空闲时)
进一步修改示例
e.g.3
1 | console.log('script start'); |
运行后输出:
1 | script start |
再修改:
e.g.4
1 | console.log('script start'); |
1 | #输出: |
这是因为
new Promise()
里接受一个函数参数function(resolve,reject)
用来执行异步执行成功或失败后的处理逻辑。
1 | let promise = new Promise(function(resolve, reject){ |
new Promise()
里的参数函数,在代码被执行到此处时可以认为是同步执行的,其返回的Promise对象使用.then链式调用时其内的函数是被异步执行。
参考:
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
https://github.com/abbshr/abbshr.github.io/issues/32
http://www.jianshu.com/p/063f7e490e9a [Promise基础]
版权声明:
本文由Lomo创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,
转载请注明作者及出处,本文作者为Lomo,本文标题为JavaScript之setTimeout.