亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

JavaScript異步編程之任務隊列

单线程

JavaScript是基于单线程的,即所有任务都需要排队,前一个任务结束,才会执行后一个任务。这样设计的原因是:JavaScript 在最开始设计的时候,其基本功能就是操作DOM节点,试想,如果一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,那么浏览器将不知道如何工作。

异步模式与事件循环

单线程最大的问题是所有任务都需要排队,如果前一个任务耗时很长,后一个任务就不得不一直等着,因此JavaScript 引入了“异步模式”。"异步模式"将所有任务分成两种:即同步任务和异步任务。同步任务指的是,在主线程上排队执行的任务;异步任务指的是,那些准备执行、被放在"任务队列"中的任务,一旦主线程上的所有同步任务执行完毕,队列中的任务就会结束等待的状态,开始执行。主线程从队列中读取任务的过程是循环不断的,这种运行机制称为Event Loop(事件循环)。

示意图:

图片描述

例子:

console.log(1);
setTimeout(function() {
    console.log(2)
}, 0);
setTimeout(function() {
    console.log(3);
}, 10);
console.log(4);
//输出:1 4 2 3

Task 队列 与 Job 队列

到了ES6 的标准,由于出现了 Promise ,ES5 时代的"同步任务"与"异步任务"已经没有办法解释其中的原理,因此出现了 task 队列与 job 队列之分。能够发布异步任务的任务源都属于 task 队列:eventajax(XMLHttpRequest)setTimeout / setInterval 都会加入task 队列中,主线程可以发布 Promise 的异步任务,因此也属于 task 队列。而 job 队列也可以称为 callback 队列,主要用来存放由任务源分配的回调函数。
下面通过例子进行详细讲解:

例子:

<button>OK</button>

console.log(1);
setTimeout(function() {
    console.log(2);
}, 0)
new Promise(function(resolve) {
    console.log(3);
    for (var i = 0; i < 1000; i++) {
        if (i = 999) {
            resolve();
        }
    }
    console.log(4);
}).then(function() {
    console.log(5);
})
document.querySelector("button").onclick = function() {
    console.log(6);
}
console.log(7);
//输出:1 3 4 7 5 2 6

首先,第一个 task 队列中的任务开始执行( 主线程 ),执行流遇到同步任务,打印出数字 1 。

console.log(1);

第二步,执行流遇到了 setTimeout ,setTimeout 为一个异步任务源,被分发到 task 队列中。

setTimeout(function() {
    console.log(2);
}, 0)

第三步,执行流遇到了创建 Promise 实例,Promise 构造函数属于同步任务,因此会依次打印出数字 3 和 4 ,而后续的 then 方法里面的回调函数则会由主线程发布到 job 队列中去。

new Promise(function(resolve) {
    console.log(3);
    for (var i = 0; i < 1000; i++) {
        if (i = 999) {
            resolve();
        }
    }
    console.log(4);
}).then(function() {
    console.log(5);
})

第四步,执行流遇到了 click 事件,click 事件为一个异步任务源,同样被分发到 task 队列中。

document.querySelector("button").onclick = function() {
    console.log(6);
}

第五步,另一个同步任务在主线程上开始执行,打印出数字 7 。

console.log(7);

第六步,此时,主线程中的同步任务执行完毕,Event Loop 开始循环 job 队列中所有可执行的回调函数,因此主线程发布的回调函数被拉到执行栈中开始执行,打印出数字 5 。

第七步,Event Loop 对 job 队列的第一轮循环结束,当然, Event Loop 会不间断地对 job 队列进行循环监听,而分发到 task 队列中的 setTimeout 在等待了给定时间之后,发布自己的任务(回调函数)到 job 队列中,Event Loop 会迅速捕捉到并拉到执行栈中执行,打印出数字 2 。

第八步,当点击事件发生时,task 队列中的 click 事件发布任务(回调函数)到 job 队列中,Event Loop 同样会迅速捕捉到并拉到执行栈中执行,打印出数字 6 。

示意图:
图片描述

注意 task 队列和 job 队列的执行顺序:
图片描述


以上内容只代表个人现阶段对于任务队列的理解。

點擊查看更多內容
1人點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
Web前端工程師
手記
粉絲
1.4萬
獲贊與收藏
860

關注作者,訂閱最新文章

閱讀免費教程

感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消