1.前言
平时开发经常会用到js异步编程,由于前端展示页面都是基于网络机顶盒(IPTV的一般性能不太好,OTT较好),目前公司主要采取的异步编程的方式有setTimeout、setInterval、requestAnimationFrame、ajax,为什么会用到异步呢,就拿业务来说,若前端全部采取同步的方式,那加载图片、生成dom、网络数据请求都会大大增加页面渲染时长。
2.JS 运行机制
JS 是单线程运行的,这意味着两段代码不能同时运行,而是必须逐步地运行,所以在同步代码执行过程中,异步代码是不执行的。只有等同步代码执行结束后,异步代码才会被添加到事件队列中。
这里就涉及到执行栈和任务队列:
同步代码是依次存放在执行栈中,遵循LIFO原则;
异步代码存放在任务队列中,任务队列又分宏任务和微任务(微任务执行优先级高于宏任务),遵循FIFO原则;
请看下面代码执行的顺序(可以先思考一下看看与正确输出顺序是否一致)
1 function foo(){ 2 console.log('start...'); 3 return bar(); 4 } 5 function bar(){ 6 console.log('bar...'); 7 } 8 //这里采用ES6的箭头函数、Promise函数 9 var promise = new Promise(function(resolve,reject){ 10 console.log('promise...'); 11 resolve(); 12 }); 13 promise.then(()=>console.log('promise resolve...')); 14 setTimeout(()=>console.log('timeout...'),0); 15 foo() 16 console.log('end...');
请看答案
promise...
start...
bar...
end...
promise resolve...
timeout...
这里分析一下(大家不要纠结任务队列的叫法,本人说明的异步微任务、异步宏任务暂无根据,理解即可,请勿深究):
程序正式开始执行是从9行初始化promise对象开始,首先打印promise...
然后往下执行发现是promise.then回调函数,此为异步微任务,放入任务队列中,等待同步任务执行完才能执行
再往下执行是timeout定时器,此为异步宏任务,也放入任务队列中,等待同步任务执行完、异步微任务才能执行
再往下是foo方法,此为同步任务,借用网络流行的一句话 “JavaScript中的函数是一等公民”,打印日志start...后回调执行bar方法,到这里就有两个执行栈了(依次将foo、bar放入栈中,bar执行完就弹出栈,foo依次弹出)
关于并发模型和Event Loop 请看MDN(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop)
3.异步编程
关于异步编程的方式,常用的定时器、ajax、Promise、Generator、async/await,详细介绍如下:
3.1.定时器
3.1.1.setTimeout与setInterval
这里拿setTimeout来举例
简单的时钟
1 (function(){ 2 var div = document.createElement('div'),timer; 3 document.body.appendChild(div); 4 //同步代码,5s后执行异步代码块显示时钟 5 //doSomething() 6 setTimeout(function(){

