Vue 源碼思想在工作中的應(yīng)用
一、背景
由于電腦CPU、內(nèi)存等的限制,能夠同時啟動的任務(wù)數(shù)有一定限制,例如一臺電腦能夠執(zhí)行5個異步任務(wù),但是目前有100個異步任務(wù)要執(zhí)行,那么如何讓這100個任務(wù)無間隔的快速執(zhí)行完畢呢?
二、問題解答
剛遇到這個問題的時候,也是出于懵逼狀態(tài),怎么處理呢???碰巧的是近期學(xué)習(xí)了一些Vue的源碼知識,那么是不是可以借鑒其思想來解決遇到的這個難題呢?經(jīng)過一步步分析,確定答案是肯定的。下面從解題思路、知識點及代碼實現(xiàn)來聊一聊實現(xiàn)過程。
2.1 解題思路
上述是整個流程圖,其流程可簡化為以下幾個步驟:
將所有任務(wù)分為兩組,任務(wù)組1指的是電腦可以并行執(zhí)行的異步任務(wù),任務(wù)組2指的是其余的異步任務(wù);
將任務(wù)組1變?yōu)榭蓭牋顟B(tài),即其發(fā)生變化時我們能夠知道;
將任務(wù)組1中的任務(wù)觸發(fā)(不觸發(fā)任務(wù)不會執(zhí)行);
某一任務(wù)執(zhí)行完畢后,將任務(wù)組2中的一個任務(wù)填充到可幀聽狀態(tài)的任務(wù)組1中;
任務(wù)按照固定數(shù)量不斷執(zhí)行,直到所有任務(wù)執(zhí)行完畢。
2.2 知識點
在Vue源碼中,Vue2.x使用Object.defineProperty()實現(xiàn)對數(shù)據(jù)的幀聽;Vue3.0使用Proxy實現(xiàn)對數(shù)據(jù)的幀聽。本著趕時髦和Proxy確實優(yōu)秀的態(tài)度,在實現(xiàn)過程中也應(yīng)用了Proxy。Proxy作為一個新的知識點,先了解一下其定義及使用方法。
2.2.1 定義
Proxy中文意思是“代理”,是在目標(biāo)對象之間架設(shè)一層“攔截”,從而可以修改某些操作的默認(rèn)行為。Proxy共支持十三種攔截操作:get、set、has、deleteProperty、ownKeys、getOwnPropertyDescriptor、defineProperty、preventExtensions、getPrototypeOf、isExtensible、setPrototypeOf、apply、construct。
2.2.2 簡單使用
- function testProxy(obj) {
- return new Proxy(obj, {
- get: (target, key) => {
- console.log(`我被get攔截器攔截了,攔截的屬性是${key}`);
- },
- set: (target, key, value) => {
- console.log(`我被set攔截器攔截了,攔截的屬性是${key}, 新值是${value}`);
- target[key] = value;
- }
- });
- }
- const testObj = {
- a: 10
- };
- const proxy = testProxy(testObj);
- proxy.a = 100;
2.2.3 詳細(xì)使用
詳細(xì)用法可以參考阮一峰大佬的“ECMAScript 6入門”。
2.3 代碼實現(xiàn)
2.3.1 定義兩個任務(wù)隊列
首先定義兩個任務(wù)隊列,task1為開始執(zhí)行的一批任務(wù),task2中為后續(xù)添加進(jìn)去的任務(wù)。
- const task1 = [1, 2, 3];
- const task2 = [4, 5, 6, 7, 8];
2.3.2 數(shù)據(jù)變?yōu)榭蓭牭暮瘮?shù)
利用Proxy將數(shù)據(jù)變?yōu)榭蓭牋顟B(tài)
- /**
- * 監(jiān)聽模塊,監(jiān)聽對應(yīng)數(shù)組的變化,保證其始終有一定長度的內(nèi)容在運行
- *
- * @param {Array} initArr 定長任務(wù)的數(shù)組
- * @param {Function} callback 對應(yīng)的回調(diào)函數(shù)
- */
- function watcher(initArr, callback) {
- const proxy = new Proxy(initArr, {
- set(target, key, value, receiver) {
- target[key] = value;
- callback(value, key, receiver);
- }
- });
- return proxy;
- }
2.3.3 異步任務(wù)邏輯
- /**
- * 異步任務(wù)的運行邏輯
- *
- * @param {number} taskIndex 異步任務(wù)的序號
- * @param {number} index 當(dāng)前任務(wù)在定長任務(wù)的序號
- * @param {Proxy} proxy Proxy實例
- */
- function asyncTask(taskIndex, index, proxy) {
- console.log(`${index}索引處的任務(wù)${taskIndex}開始執(zhí)行`);
- return new Promise(resolve => {
- setTimeout(() => {
- console.log(`${index}索引處的任務(wù)${taskIndex}執(zhí)行完畢`);
- // 當(dāng)任務(wù)隊列2中還有任務(wù)時,進(jìn)入隊列替換任務(wù)1中執(zhí)行完的任務(wù)
- if (task2.length > 0) {
- proxy[index] = task2.shift();
- }
- }, 1000 + 2000 * Math.random());
- });
- }
2.3.4 主函數(shù)
- const proxy = watcher(task1, asyncTask);
- task1.forEach((taskIndex, index) => asyncTask(taskIndex, index, proxy));
- }
2.3.5 執(zhí)行結(jié)果
通過結(jié)果可以看到,當(dāng)一個任務(wù)完成時立刻將有一個新的任務(wù)進(jìn)入。
- 0索引處的任務(wù)1開始執(zhí)行
- 1索引處的任務(wù)2開始執(zhí)行
- 2索引處的任務(wù)3開始執(zhí)行
- 0索引處的任務(wù)1執(zhí)行完畢
- 0索引處的任務(wù)4開始執(zhí)行
- 2索引處的任務(wù)3執(zhí)行完畢
- 2索引處的任務(wù)5開始執(zhí)行
- 1索引處的任務(wù)2執(zhí)行完畢
- 1索引處的任務(wù)6開始執(zhí)行
- 0索引處的任務(wù)4執(zhí)行完畢
- 0索引處的任務(wù)7開始執(zhí)行
- 2索引處的任務(wù)5執(zhí)行完畢
- 2索引處的任務(wù)8開始執(zhí)行
- 1索引處的任務(wù)6執(zhí)行完畢
- 0索引處的任務(wù)7執(zhí)行完畢
- 2索引處的任務(wù)8執(zhí)行完畢
三、討論
針對此類問題的處理方式,各位大佬有新的思路與方法歡迎留言,我們一起討論,共同進(jìn)步。
本文轉(zhuǎn)載自微信公眾號「前端點線面」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系前端點線面公眾號。





























