js异步
来源:互联网 发布:java用什么笔记本 编辑:程序博客网 时间:2024/06/06 14:01
js异步编程读书笔记(一)
js提供的异步函数包括两类:
1)I/O函数:js采用的是非阻塞式I/O,需要我们添加事件处理器,使用回调函数来实现阻塞。(node.js——事件驱动型服务器框架)
2)计时函数:setTimeout、setInterval(不精确,触发频率较慢约200次/s);
若想实现细粒度计时:- node:使用 process.nextTick,触发频率约10万次/s
- requestAnimationFrame js动画函数——支持(ie9+)浏览器,60+帧/s的速度运行js动画,同时避免后台选项卡运行这些动画,节约CPU周期。
js事件处理器在线程空闲之前不会运行,eg1:
var start=new Date(); setTimeout(function(){ var end=new Date(); console.log("time spend:",(end-start),"ms"); },500); while(new Date-start<1000){};
结果分析:
- 运行的结果均随机>1000ms,因为setTimeout回调在while循环结束后才被触发。
- 调用延时函数时,会将延时事件加入事件队列,回调执行的时间取决于队列中之前的事件的执行速度,可见setTimeout、setInterval计时精度不准。
- 表示的延迟时间并不代表到时候一定会执行动画代码,而仅代表到时候会把代码添加到任务队列中。如果 UI 线程繁忙,比如忙于处理用户操作,那么即使把代码加入队列也不会立即执行。
eg2:常见的for循环中使用计时函数,会出现叹为观止的结果:
for (var i = 1; i < 6; i++) { setTimeout(function timer(){ //计时函数 alert(i);//输出6,6,6,6,6 },1000*i);//每秒执行一次 console.log(i);//for循环线程控制台打印结果 }
按照思维定式:我们会预期计时函数执行结果与for循环控制台打印结果一致,均为1,2,3,4,5;然而结果却与设想大相径庭:计时函数的执行结果竟然为5个6;原因如上所示:
- 即使在循环中,延迟函数的回调也要在循环结束时才执行
- 循环过程中,延迟函数会加入到事件队列中排队等待,for循环执行完毕后,i=6,此时开始执行队列中的延时事件,setTimeout()调用其中的回调函数,回调函数形成了闭包,保持对外部作用域变量i的引用,因此队列中的延时函数执行时都调用的是i=6这个值,最终输出5个6.
- 即使把定时器的时延改为0,setTimeout(…,0);依旧要异步等待,所有回调函数依旧在循环结束后才执行,且结果同上。
- 此种方式还会带来其他头疼的问题,如果加入事件队列中的计时事件很多,当队列中的事件正在执行过程中,我们想停止它们的执行,刷新页面后,未完成的延时事件会继续执行,无法达到立即停止的效果,这样用户体验会很差。
如果想得到我们预期的结果,应该怎样修改循环体呢?
可以通过声明匿名函数并立即调用来创建一个新的作用域,在每次循环中把新的作用域封闭起来,把外部变量赋给封闭作用域内的一个新变量,这样就可以在每次循环中正常执行延时函数的回调函数,代码如下所示:
//解决循环中延时函数无法立即执行的问题 for (var i = 1; i < 6; i++) { (function(j){ setTimeout(function timer(){ alert(j);//输出1,2,3,4,5 },1000*j); })(i); //console.log(i); }
可以看出,得到了我们需要的结果。如果把延时时间j*1000改成1000,又会出现神奇的结果,第一次循环输出1后,后面几次循环输出的数字不一定按顺序,可能会随机变化,比如1,3,2,5,4.如果需要严格按序执行,这样的结果可能会带来较严重的问题。出现此情况的原因:每次循环延时函数的延时时间相同,导致事件加入队列等待执行时间出现冲突,因此结果会随机变化。为避免这种情况,依旧需要采用j*1000这种模式,保证每个延时事件有间隔(理想情况下每隔1s)的执行。
3. requestAnimationFrame(HTML5):
- 常用于js动画,方便浏览器确定重绘的最佳方式。浏览器都会对重绘操作加以限制,不超过显示器的重绘频率(60Hz),因此最平滑动画的最佳循环间隔是 1000ms/60,约17ms。
- 是一个全局函数。调用requestAnimationFrame后,它会要求浏览器根据自己的频率进行一次重绘,它接收一个回调函数作为参数,在即将开始的浏览器重绘时,会调用这个函数,并会给这个函数传入调用回调函数时的时间作为参数。由于requestAnimationFrame的功效只是一次性的,所以若想达到动画效果,则必须连续不断的调用requestAnimationFrame
- requestID = window.requestAnimationFrame(callback); // Firefox 23 / IE10 / Chrome / Safari 7 (incl. iOS)
requestID :可以作为参数传给window.cancelAnimationFrame() 来取消这个回调函数。
- callback:在每次需要重新绘制动画时,会调用这回调函数。这个回调函数会收到一个参数,这个 DOMHighResTimeStamp 类型的参数指示当前时间距离开始触发 requestAnimationFrame 的回调的时间。
- 如下是MDN开发者网络上面给出的兼容各浏览器的demo:
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; var start = null; var d = document.getElementById('SomeElementYouWantToAnimate'); function step(timestamp) { if (start === null) start = timestamp; var progress = timestamp - start; d.style.left = Math.min(progress/10, 200) + "px"; if (progress < 2000) { / requestAnimationFrame(step);//重复调用requestAnimationFrame实现动画循环效果 } } requestAnimationFrame(step);//step表示实现动画操作的回调函数
web worker(HTML5)
- 是运行在后台的 JavaScript,不会影响页面的性能。(除了IE)在网页外单独开启一个线程执行任务,可缓存结果。
- 一旦它被创建,Web Workers就可以通过postMessage()向任务池发送任务请求,执行完之后再通过postMessage()返回消息给创建者指定的事件处理程序(通过onmessage进行捕获)。
- Web Workers进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用XMLHttpRequest来处理I/O,无论responseXML和channel属性是否为null。
- web worker 位于外部文件中,它们无法访问下例 JavaScript 对象:window 对象、 document 对象、parent 对象。
- 深入理解参考:http://blog.csdn.net/i10630226/article/details/51536404 (多线程处理)
下面的例子创建了一个简单的 web worker,在后台计数:
<!DOCTYPE html><html><body><p>Count numbers: <output id="result"></output></p><button onclick="startWorker()">Start Worker</button><button onclick="stopWorker()">Stop Worker</button><br /><br /><script>var w; //worker对象function startWorker(){if(typeof(Worker)!=="undefined"){ if(typeof(w)=="undefined") { w=new Worker("demo_workers.js"); //检测是否存在worker,如不存在,创建一个新的worker对象,并执行"demo_workers.js" } w.onmessage = function (event) { //添加"onmessage"事件监听器" document.getElementById("result").innerHTML=event.data; //当web worker传递消息时,会执行事件监听器中的代码" };}else{document.getElementById("result").innerHTML="Sorry, your browserdoes not support Web Workers...";}}function stopWorker(){w.terminate(); //终止web worker,并释放浏览器/计算机资源}</script></body></html>
//外部"demo_workers.js"文件内容:var i=0;function timedCount(){i=i+1;postMessage(i); //用于向 HTML 页面传回一段消息setTimeout("timedCount()",500);}timedCount();
以上为部分读书笔记的总结,后续完善内容待补充……
参考书籍及js异步编程相关链接
《JavaScript异步编程:设计快速响应的网络应用》
《you don’t know js》
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
- js异步
- js异步
- JS异步
- 异步JS -- 异步控制台解惑
- 异步加载JS文件
- js 异步处理进度条
- Ext异步加载JS
- 异步 JS拦截技术
- js 异步 多线程 技术
- js异步删除
- js异步队列函数
- 异步加载JS
- js异步编程学习
- js异步加载
- js 异步提交表单
- 异步创建JS
- js异步加载
- 异步加载js方案
- 练习2-1 编写一个程序以确定分别由signed及unsigned限定的char、short、int、与long类型变量的取值范围
- MFC滚动字幕实现
- sqlite基本用法
- iOS 【.pch文件的路径方便设置】
- 实用的但偏执的Java编程技术10个分享
- js异步
- 2016"百度之星" - 初赛(Astar Round2B)1001 1003~1006
- Codeforces #187Div2
- 机器学习源码收集
- JavaScript之DOM实践
- Excel导出工具类.
- 高并发处理
- const, static, inline, #define的用法以及关系
- 源码安装mysql-5.1.72