之前我们讨论过JS代码执行的同步和异步,JS的单线程执行机制不会改变;但是仅仅懂得同步异步是远远不够的;比如说下面这些代码:
1 setTimeout(function(){ 2 console.log("1"); 3 }); 4 new Promise(function(resolve,reject){ 5 console.log("2"); 6 resolve(); 7 }).then(function(){ 8 console.log("3"); 9 }) 10 console.log("4");
由于同步和异步的影响,我们会自信的说出打印结果是: 2,3,4,1;可是呢,用Chrome打开运行代码,蒙了,打印的竟然是:2 ,4 ,3,1;
这就不得不引出我们即将讨论的主角:宏任务和微任务;简单来说:JS中,大部分代码被分配到宏任务排队执行,但像Promise.then、process.nextTick()等微任务;我们就拿Promise.then来举例说明。根据先执行微任务再执行宏任务的机制;还是上面那段代码,我们简单的分析一下:
setTimeout(function(){ console.log("1"); }); new Promise(function(resolve,reject){ console.log("2"); resolve(); }).then(function(){ console.log("3"); }) console.log("4");
这些代码整体作为一个宏任务开始执行,还是按照先同步,后异步的规则,遇到延时定时器,是个异步代码,先挂起来不执行;接着遇到Promise的实例化对象,属于同步任务,立即执行,打印一个2;接下来遇到实例化对象的微任务,但后面还有一个同步代码,依然是先执行同步代码,打印4;接下来一轮跑完了,我们回头看,有一个延时定时器,还有一个微任务,先执行微任务,打印出3,最后打印1;就像跑了第二遍一样,这就是一个最简单的时间循环(event Loop);
接下来写一段稍微复杂的,读者们可以一起思考一下:
console.log('1'); setTimeout(function () { console.log('2'); new Promise(function (resolve) { console.log('3'); resolve(); }).then(function () { console.log('4') }) }) new Promise(function (resolve) { console.log('5'); resolve(); }).then(function () { console.log('6') }) setTimeout(function () { console.log('7'); new Promise(function (resolve) { console.log('8'); resolve(); }).then(function () { console.log('9') }) }) console.log('10');
整段代码作为一个宏任务,先执行同步代码,所以第一次时间循环后会打印出:1,5,10;接下来发现有微任务:打印一个6;开始第二轮循环,2个异步代码并且都是立即执行的延时定时器,我们就按照从上到下的顺序执行,先看第一个定时器(此时这就是一个宏任务):会打印出2,3;然后执行微任务,打印4;最后看第二个定时器:一次打印:7,8,9;over;
再此感谢掘金的ssssyoki大神的讲解,再加上自己的一些理解;希望这篇文章可以对你带来些许帮助;