vue3調度器scheduler功能和用法詳解
更新時間:2023年06月05日 10:02:27 作者:包子愛吃肉
調度器是vue3響應式系統(tǒng)中一個非常重要的特性,可調度性指的是當trigger 動作觸發(fā)副作用函數重新執(zhí)行時,有能力決定副作用函數執(zhí)行的時機、次數以及方式,本文通過代碼示例給大家介紹調度器是什么,有什么功能,怎么使用,感興趣的同學可以借鑒閱讀
調度器是vue3響應式系統(tǒng)中一個非常重要的特性,可調度性指的是當trigger 動作觸發(fā)副作用函數重新執(zhí)行時,有能力決定副作用函數執(zhí)行的時機、次數以及方式
const data = { foo: 1 }
const obj = new Proxy(data, { /* ... */ }) // 上文中的響應式
effect(() => {
console.log(obj.foo)
})
obj.foo++
console.log('結束了')正常執(zhí)行結果順序是1,2,結束了,但是,若我們期望的打印順序發(fā)生改變1,結束了,2,要實現這樣的打印結果,就需要使用到調度器
- 可以為函數effect函數設計一個選項參數
options,允許用戶指定調度器:
effect(
() => {
console.log(obj.foo);
},
// options
{
// 調度器 scheduler 是一個函數
scheduler(fn) {
// ...
},
});- 將調度器對象掛在到當前副作用函數中
// effect 函數用于注冊副作用函數
function effect(fn, options = {}) {
fn.options = options; // 新增掛在調度器
activeEffect = fn;
// 執(zhí)行副作用函數
fn();
}- 修改參數時,判斷是否存在調度器,存在,執(zhí)行當前掛載中調度器方法
(在taigger函數中)
function trigger(target, key) {
// 根據target從桶中取得depsMap,它是key --> effects
const depsMap = bucket.get(target);
if (!depsMap) return;
// 根據key取得當前對應的副作用函數
const effects = depsMap.get(key);
// 執(zhí)行副作用函數
effects && effects.forEach((fn) => {
// fn()
if (fn.options.scheduler) { // 新增
fn.options.scheduler(fn);
} else {
// 否則直接執(zhí)行副作用函數(之前的默認行為)
fn();
}
});
}- 使用
setTimeout開啟一個宏任務來執(zhí)行副作用函數 fn,這樣,就能改變執(zhí)行順序,拿到我們想要的執(zhí)行結果
function effect(fn, options = {}) {
fn.options = options; // 新增
activeEffect = fn;
// 執(zhí)行副作用函數
fn();
}
effect(
() => {
console.log(obj.foo);
},
// options
{
// 調度器 scheduler 是一個函數
scheduler(fn) {
// 修改參數,將副作用函數放在宏任務隊列中執(zhí)行
setTimeout(fn)
},
}
);完整代碼:
const data = { foo: 1 };
// 用一個全局變量存儲被注冊的副作用函數
let activeEffect;
// 創(chuàng)建一個新桶來存儲副作用函數,包含key和value
const bucket = new WeakMap();
const obj = new Proxy(data, {
get(target, key) {
// target:當前對象,key:觸發(fā)監(jiān)聽的key
track(target, key);
return target[key];
},
set(target, key, newVal) {
target[key] = newVal;
trigger(target, key);
},
});
// track函數
function track(target, key) {
// 沒有正在執(zhí)行的副作用函數 直接返回
if (!activeEffect) return target[key];
// 從這個桶中取出一個Map類型(key -> value)
let depsMap = bucket.get(target);
// 不存在,則創(chuàng)建一個Map與target關聯
if (!depsMap) {
bucket.set(target, (depsMap = new Map()));
}
// 根據key判斷每個key上是否存在對應的副作用函數
let deps = depsMap.get(key);
// 不存在,則新建一個new Set,并與key關聯
if (!deps) {
depsMap.set(key, (deps = new Set()));
}
// 最后將當前激活的副作用函數添加到桶中
deps.add(activeEffect);
}
// trigger函數
function trigger(target, key) {
// 根據target從桶中取得depsMap,它是key --> effects
const depsMap = bucket.get(target);
if (!depsMap) return;
// 根據key取得當前對應的副作用函數
const effects = depsMap.get(key);
// 執(zhí)行副作用函數
effects &&
effects.forEach((fn) => {
if (fn.options.scheduler) {
fn.options.scheduler(fn);
} else {
// 否則直接執(zhí)行副作用函數(之前的默認行為)
fn();
}
});
}
// effect 函數用于注冊副作用函數
function effect(fn, options = {}) {
fn.options = options; // 新增
activeEffect = fn;
// 執(zhí)行副作用函數
fn();
}
effect(
() => {
console.log(obj.foo);
},
// options
{
// 調度器 scheduler 是一個函數
scheduler(fn) {
// 修改參數,將副作用函數放在宏任務隊列中執(zhí)行
setTimeout(fn);
},
}
);
obj.foo++;
console.log("結束了");除了控制副作用函數的執(zhí)行順序,通過調度器還可以做到控制它的執(zhí)行次數
- 正常的打印結果應該是
1,2,3,但是我們只關心執(zhí)行的最后結果,應該拿到的是1,3,執(zhí)行三次有些多余,這時,就需要使用到調度器來修改執(zhí)行次數
const data = { foo: 1 }
const obj = new Proxy(data, { /* ... */ }) // 上文中的響應式
effect(() => {
console.log(obj.foo)
})
obj.foo++
obj.foo++;- 實現不包含過渡階段,使用調度器基于
promise,可以直接修改當前當前調度函數
// 定義一個任務隊列,使用它自動去重能力
const jobQueue = new Set();
// 使用 Promise.resolve() 創(chuàng)建一個 promise 實例,我們用它將一個任務添加到微任務隊列
const p = Promise.resolve();
// 一個標志代表是否正在刷新隊列
let isFlushing = false;
function flushJob() {
// 如果隊列正在刷新,則什么都不做
if (isFlushing) return;
// 設置為 true,代表正在刷新
isFlushing = true;
// 在微任務隊列中刷新 jobQueue 隊列
p.then(() => {
jobQueue.forEach((job) => job());
}).finally(() => {
// 結束后重置 isFlushing
isFlushing = false;
});
}- 執(zhí)行調度函數
effect(
() => {
console.log(obj.foo);
},
// options
{
// 調度器 scheduler 是一個函數
scheduler(fn) {
jobQueue.add(fn);
// 調用 flushJob 刷新隊列
flushJob();
},
}
);
obj.foo++;
obj.foo++;到此這篇關于vue3調度器scheduler功能和用法詳解的文章就介紹到這了,更多相關vue3調度器scheduler內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue3+vite+tdesign實現日歷式可編輯的排課班表填寫功能
本文介紹了如何使用Vue3和tdesign實現一個日歷式、可編輯的排班填寫功能,開發(fā)過程中面臨了年份和月份下拉框的實現、周期顯示以及可編輯日歷的樣式和數據獲取等挑戰(zhàn),感興趣的朋友一起看看吧2025-01-01
一文解決vue2 element el-table自適應高度問題
在寫公司后臺項目的時候遇到一個需求,要求表格頁面不能有滾動條,所以必須封裝一個公共方法來實現表格自適應高度,本問小編給大家介紹了如何解決vue2 element el-table自適應高度問題,需要的朋友可以參考下2023-11-11

