大家看下如下代码,猜猜执行结果:
var start = new Date; setTimeout(function(){ console.log('时间流逝了:'+(new Date - start)+'毫秒'); }, 200); while (new Date - start < 1000) {} console.log(1); function doSoming(){ setTimeout(function(){ console.log('时间又流逝了:'+(new Date - start)+'毫秒'); },10); } doSoming(); while (new Date - start < 2000) {} console.log(2);
结果是:
约1秒后输出:1,
再过约1秒后输出:2,
接着才立即输出:时间流逝了: 2002 毫秒
最后输出:时间又流逝了: 2003 毫秒
您猜对了没?
这里通过setTimeout来延迟执行的函数都被推到最后才执行了;
原理如下:
在现有浏览器环境中,Javascript执行引擎是单线程的,主线程的语句和方法,会阻塞定时任务的运行,在Javascript执行引擎之外,存在一个任务队列,当在代码中调用setTimeout()方法时,注册的延时方法会挂到浏览器内核其他模块处理,当延时方法到达触发条件,即到达设置的延时时间时,该模块再将要执行的方法添加至该模块的任务队列中。这一过程与执行引擎主线程独立,执行引擎在主线程方法执行完毕,到达空闲状态时,才会从该模块的任务队列中顺序提取任务来执行,这期间的时间,可能大于注册任务时设置的延时时间;
浏览器在空闲状态下,会不断的尝试从模块的任务队列中提取任务,这称为事件循环模型;
再回头看下前面的代码,第二个setTimeout()的延迟方法的延迟时间是10毫秒,比第一个要早触发啊!为什么执行结果却在后面?因为它被之前的代码阻塞了约1000.5~1001毫秒了(视浏览器的处理速度),等他挂到处理模块,等到触发时间添加进任务队列时,第一个setTimeout()的延迟方法早就被添加到模块的任务队了,而引擎主线程是按顺序提取得,所以,你应该懂了吧?
现在,如果把上面的while (new Date - start < 1000) {}改成while (new Date - start < 189) {}或者是while (new Date - start < 190) {},结果又是什么?我就不多说了!各刷新浏览器20遍,自己看结果吧!
而setInterval()方法和setTimeout()地位是相同的,调用setInterval()方法时,注册的延时方法挂到模块处理,每当触发时间到达,就往任务队列添加一次要执行的方法;
下面来具体看看setTimeout的语法:
var timeID = window.setTimeout(func,delay,[param1,param2,...]);
var timeID = window.setTimeout(code,delay);
setTimeout和setInterval是Window对象的方法(可省略window),第二个之后的可选参数(IE9及旧版不支持)是传递给func的参数,每次调用他们时都会返回一个数字ID(在浏览器中打印出来就只是个数字,而本人在webstorm中打印出来发现它实际是一个对象,有很多个属性),这个ID保持着它对应的setTimeout或setInterval的相关信息,主要用来在中模块中和任务队列中清除(或关闭)掉它们(用方法clearTimeout(ID)和clearInterval(ID))。
如果你需要向你的回调函数内传递一个参数以下是兼容IE的写法
if (document.all && !window.setTimeout.isPolyfill) { var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay, param1, param2,param3) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function "htmlcode">for(var i =0; i <10; i++){ setTimeout(function(){ console.log(i); },1000); }上面的代码只会输出数字 10 十次。为什么?闭包!
当 console.log 被调用的时候,虽然匿名函数保持对外部变量 i 的引用,但此时 for循环已经结束, i 的值被修改成了 10.
为了得到想要的结果,需要在每次循环中创建变量 i 的拷贝。
为了正确的获得循环序号,最好使用 匿名包裹器(其实就是我们通常说的自执行匿名函数)。
for(var i =0; i <10; i++){ (function(e){ setTimeout(function(){ console.log(e); },1000); })(i); }外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了 i 的一个拷贝。
当传递给 setTimeout 的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。
有另一个方法完成同样的工作;那就是从匿名包装器中返回一个函数。这和上面的代码效果一样。for(var i =0; i <10; i++){ setTimeout((function(e){ return function(){ console.log(e); } })(i),1000) }还有一个重要应用:函数节流(throttle)与函数去抖(debounce)
请看我从网上收集的一些资料:
JavaScript-性能优化之函数节流(throttle)与函数去抖(debounce)
参考链接:
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout
http://www.alloyteam.com/2015/10/turning-to-javascript-series-from-settimeout-said-the-event-loop-model/#prettyPhoto以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]