Biasanya kami tidak akan menggunakan effect secara langsung, kerana effect ialah API tahap rendah Apabila kami menggunakan Vue3, Vue akan memanggil effect untuk kami secara lalai. Kesan diterjemahkan sebagai kesan, yang bermaksud untuk menjadikannya berfungsi Fungsi yang menjadikannya berfungsi adalah fungsi yang kita lalui, jadi fungsi kesan adalah untuk menjadikan fungsi yang kita lalui berkuat kuasa, iaitu, untuk melaksanakan fungsi ini. Gambar rajah ringkas proses pelaksanaan adalah seperti berikut:
Seterusnya, kita akan terlebih dahulu memahami penggunaan asas kesan melalui contoh, dan kemudian memahami prinsipnya.
1. Penggunaan kesan
1. Penggunaan asas
const obj = reactive({count: 1}) const runner = effect(() => { console.log(obj.count) }) obj.count++
Hasilnya akan mencetak 1 dahulu, dan kemudian mencetak 2 selepas obj.count++
.
Rajah proses adalah seperti berikut:
Jalankan effect(fun)
// 先执行 fun() // 打印出1 const runner = new ReactiveEffect(fn) return runner runner: { run() { this.fun() //执行fun }, stop() { } }
console.log(obj.count)
Struktur pengumpulan pergantungan trek adalah seperti berikut :
obj.count++
mencetuskan kebergantungan dan melaksanakan runner.run(). > dicetak keluar. 2. atribut malas adalah benar
Apabila nilai ini benar, panggilan balik kesan akan dilaksanakan secara automatik hanya apabila data bergantung berubah selepas pelari dipanggil secara manual untuk kali pertama boleh difahami bahawa kesannya adalah kali pertama selepas pelari dipanggil secara manual. Melaksanakan
() => { console.log(obj.count) }
hanya akan mencetak 2
Sebabnya ialah kod sumber kesan mempunyai logik berikut:
3 pilihan mengandungi onTrackconst obj = reactive({count: 1}) const runner = effect(() => { console.log(obj.count) }, { lazy: true }) runner() obj.count++

let events = [] const onTrack = (e) => { events.push(e) } const obj = reactive({ foo: 1, bar: 2 }) const runner = effect( () => { console.log(obj.foo) }, { onTrack } ) console.log('runner', runner) obj.foo++ console.log("events", events)2. Analisis kod sumber
1. Pelaksanaan kaedah kesan
[ { effect: runner, // effect 函数的返回值 target: toRaw(obj), // 表示的是哪个响应式数据发生了变化 type: TrackOpTypes.GET, // 表示此次记录操作的类型。 get 表示获取值 key: 'foo' } ]
Kod teras:
Buat fungsi kesan sampingan yang responsif
, dan hasil yang dijalankan adalah seperti berikut:const _effect = new ReactiveEffect(fn)
// packages/reactivity/src/effect.ts export interface ReactiveEffectOptions extends DebuggerOptions { lazy?: boolean scheduler?: EffectScheduler scope?: EffectScope allowRecurse?: boolean onStop?: () => void } export function effect<T = any>( fn: () => T, // 副作用函数 options?: ReactiveEffectOptions // 结构如上 ): ReactiveEffectRunner { // 如果 fn 对象上有 effect 属性 if ((fn as ReactiveEffectRunner).effect) { // 那么就将 fn 替换为 fn.effect.fn fn = (fn as ReactiveEffectRunner).effect.fn } // 创建一个响应式副作用函数 const _effect = new ReactiveEffect(fn) if (options) { // 将配置项合并到响应式副作用函数上 extend(_effect, options) // 如果配置项中有 scope 属性(该属性的作用是指定副作用函数的作用域) if (options.scope) recordEffectScope(_effect, options.scope) } if (!options || !options.lazy) { // options.lazy 不为true _effect.run() // 执行响应式副作用函数 首次执行fn() } // _effect.run作用域绑定到_effect const runner = _effect.run.bind(_effect) as ReactiveEffectRunner // 将响应式副作用函数赋值给 runner.effect runner.effect = _effect return runner }
skop terikat kepada _effect.run()
if (!options || !options.lazy) { // options.lazy 不为true _effect.run() // 执行响应式副作用函数 首次执行fn() }
dan mengembalikan pelari fungsi kesan sampingan_effect.run
_effect
2. Kod sumber fungsi ReactiveEffect
// _effect.run作用域绑定到_effect const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
Fungsi kaedah larian adalah untuk melaksanakan fungsi kesan sampingan , dan dalam proses melaksanakan fungsi kesan sampingan, kebergantungan akan dikumpulkan; dikumpul;
activeEffect dan ini tidak sama setiap kali, kerana activeEffect akan berubah dengan kedalaman timbunan panggilan, sementara ini ditetapkan ;
-
3. Berkaitan koleksi kebergantungan
1. Bagaimana untuk mencetuskan pengumpulan kebergantungan -
Dalam fungsi kesan sampingan,
akan mencetuskan pengumpulan kebergantungan
export class ReactiveEffect<T = any> { active = true deps: Dep[] = [] // 响应式依赖项的集合 parent: ReactiveEffect | undefined = undefined /** * Can be attached after creation * @internal */ computed?: ComputedRefImpl<T> /** * @internal */ allowRecurse?: boolean /** * @internal */ private deferStop?: boolean onStop?: () => void // dev only onTrack?: (event: DebuggerEvent) => void // dev only onTrigger?: (event: DebuggerEvent) => void constructor( public fn: () => T, public scheduler: EffectScheduler | null = null, scope?: EffectScope ) { // 记录当前 ReactiveEffect 对象的作用域 recordEffectScope(this, scope) } run() { // 如果当前 ReactiveEffect 对象不处于活动状态,直接返回 fn 的执行结果 if (!this.active) { return this.fn() } // 寻找当前 ReactiveEffect 对象的最顶层的父级作用域 let parent: ReactiveEffect | undefined = activeEffect let lastShouldTrack = shouldTrack // 是否要跟踪 while (parent) { if (parent === this) { return } parent = parent.parent } try { // 记录父级作用域为当前活动的 ReactiveEffect 对象 this.parent = activeEffect activeEffect = this // 将当前活动的 ReactiveEffect 对象设置为 “自己” shouldTrack = true // 将 shouldTrack 设置为 true (表示是否需要收集依赖) // effectTrackDepth 用于标识当前的 effect 调用栈的深度,执行一次 effect 就会将 effectTrackDepth 加 1 trackOpBit = 1 << ++effectTrackDepth if (effectTrackDepth <= maxMarkerBits) { // 初始依赖追踪标记 initDepMarkers(this) } else { // 清除依赖追踪标记 cleanupEffect(this) } // 返回副作用函数执行结果 return this.fn() } finally { // 如果 effect调用栈的深度 没有超过阈值 if (effectTrackDepth <= maxMarkerBits) { // 确定最终的依赖追踪标记 finalizeDepMarkers(this) } // 执行完毕会将 effectTrackDepth 减 1 trackOpBit = 1 << --effectTrackDepth // 执行完毕,将当前活动的 ReactiveEffect 对象设置为 “父级作用域” activeEffect = this.parent // 将 shouldTrack 设置为上一个值 shouldTrack = lastShouldTrack // 将父级作用域设置为 undefined this.parent = undefined // 延时停止,这个标志是在 stop 方法中设置的 if (this.deferStop) { this.stop() } } } stop() { // stopped while running itself - defer the cleanup // 如果当前 活动的 ReactiveEffect 对象是 “自己” // 延迟停止,需要执行完当前的副作用函数之后再停止 if (activeEffect === this) { // 在 run 方法中会判断 deferStop 的值,如果为 true,就会执行 stop 方法 this.deferStop = true } else if (this.active) {// 如果当前 ReactiveEffect 对象处于活动状态 cleanupEffect(this) // 清除所有的依赖追踪标记 if (this.onStop) { this.onStop() } this.active = false // 将 active 设置为 false } } }Entri yang dicetuskan berada dalam pemintas get
const runner = effect(() => {
console.log(obj.count)
})
2. objek yang baru sahaja kita bincangkan, yang menunjuk kepada fungsi kesan sampingan yang sedang dilaksanakan fungsi kaedah trek adalah untuk mengumpul kebergantungan, dan pelaksanaannya sangat mudah, cuma rekodkannya dalam targetMap Next, target dan key; obj.count
targetMap ialah WeakMap, kuncinya ialah sasaran, dan nilainya ialah Peta ini ialah kunci, dan nilainya ialah
Struktur pseudocode Seperti berikut:
function createGetter(isReadonly = false, shallow = false) { // 闭包返回 get 拦截器方法 return function get(target: Target, key: string | symbol, receiver: object) { // ... if (!isReadonly) { track(target, TrackOpTypes.GET, key) } // ... }Di atas ialah depMap asalpersekitaran pembangun akan menambah
const targetMap = new WeakMap(); /** * 收集依赖 * @param target target 触发依赖的对象,例子中的obj * @param type 操作类型 比如obj.count就是get * @param key 指向对象的key, 比如obj.count就是count */ export function track(target: object, type: TrackOpTypes, key: unknown) { if (shouldTrack && activeEffect) { // 是否应该依赖收集 & 当前的new ReactiveEffect()即指向的就是当前正在执行的副作用函数 // 如果 targetMap 中没有 target,就会创建一个 Map let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key) if (!dep) { depsMap.set(key, (dep = createDep())) // createDep 生成dep = { w:0, n: 0} } const eventInfo = __DEV__ ? { effect: activeEffect, target, type, key } : undefined trackEffects(dep, eventInfo) } }
eventInfo untuk meningkatkan penyahpepijatan responsif Strukturnya adalah seperti berikut:
eventInfo
trackEffects(dep, eventInfo)
trackEffects
4. Pencetus kebergantungan
Sebagai contoh, kod dalam contoh
Ia akan mencetuskan pemintasan set dan mencetuskan kemas kini pergantunganfunction createSetter(shallow = false) { return function set( target: object, key: string | symbol, value: unknown, receiver: object ): boolean { //... const result = Reflect.set(target, key, value, receiver) // don't trigger if target is something up in the prototype chain of original if (target === toRaw(receiver)) { if (!hadKey) { trigger(target, TriggerOpTypes.ADD, key, value) // 触发ADD依赖更新 } else if (hasChanged(value, oldValue)) { trigger(target, TriggerOpTypes.SET, key, value, oldValue) //触发SET依赖更新 } } //... }
1、trigger依赖更新
// 路径:packages/reactivity/src/effect.ts export function trigger( target: object, type: TriggerOpTypes, key?: unknown, newValue?: unknown, oldValue?: unknown, oldTarget?: Map<unknown, unknown> | Set<unknown> ) { const depsMap = targetMap.get(target) // 获取depsMap, targetMap是在track中创建的依赖 if (!depsMap) { // never been tracked return } let deps: (Dep | undefined)[] = [] if (type === TriggerOpTypes.CLEAR) { // collection being cleared // trigger all effects for target deps = [...depsMap.values()] } else if (key === 'length' && isArray(target)) { const newLength = Number(newValue) depsMap.forEach((dep, key) => { if (key === 'length' || key >= newLength) { deps.push(dep) } }) } else { // schedule runs for SET | ADD | DELETE if (key !== void 0) { deps.push(depsMap.get(key)) } // also run for iteration key on ADD | DELETE | Map.SET switch (type) { case TriggerOpTypes.ADD: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } else if (isIntegerKey(key)) { // new index added to array -> length changes deps.push(depsMap.get('length')) } break case TriggerOpTypes.DELETE: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } break case TriggerOpTypes.SET: if (isMap(target)) { deps.push(depsMap.get(ITERATE_KEY)) } break } } const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } } else { const effects: ReactiveEffect[] = [] for (const dep of deps) { if (dep) { effects.push(...dep) } } if (__DEV__) { triggerEffects(createDep(effects), eventInfo) } else { triggerEffects(createDep(effects)) } } }
const depsMap = targetMap.get(target)
获取 targetMap 中的 depsMap targetMap结构如下:
执行以上语句之后的depsMap结构如下:
将 depsMap 中 key 对应的 ReactiveEffect 对象添加到 deps 中deps.push(depsMap.get(key))
之后的deps结构如下:
triggerEffects(deps[0], eventInfo)
const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } }
trigger函数的作用就是触发依赖,当我们修改数据的时候,就会触发依赖,然后执行依赖中的副作用函数。
在这里的实现其实并没有执行,主要是收集一些需要执行的副作用函数,然后在丢给triggerEffects函数去执行,接下来看看triggerEffects函数。
2、triggerEffects(deps[0], eventInfo)
export function triggerEffects( dep: Dep | ReactiveEffect[], debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { // spread into array for stabilization const effects = isArray(dep) ? dep : [...dep] for (const effect of effects) { if (effect.computed) { triggerEffect(effect, debuggerEventExtraInfo) } } for (const effect of effects) { if (!effect.computed) { triggerEffect(effect, debuggerEventExtraInfo) } } }
主要步骤
const effects = isArray(dep) ? dep : [...dep]
获取effects
triggerEffect(effect, debuggerEventExtraInfo)
执行effect,接下来看看源码
3、triggerEffect(effect, debuggerEventExtraInfo)
function triggerEffect( effect: ReactiveEffect, debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { if (effect !== activeEffect || effect.allowRecurse) { // 如果 effect.onTrigger 存在,就会执行,只有开发模式下才会执行 if (__DEV__ && effect.onTrigger) { effect.onTrigger(extend({ effect }, debuggerEventExtraInfo)) } // 如果 effect 是一个调度器,就会执行 scheduler if (effect.scheduler) { effect.scheduler() } else { // 其它情况执行 effect.run() effect.run() } } }
effect.run()就是执行副作用函数
Atas ialah kandungan terperinci Cara menggunakan kesan teras responsif Vue3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Vue.js adalah kerangka depan, dan rangka kerja belakang digunakan untuk mengendalikan logik sisi pelayan. 1) Vue.js memberi tumpuan kepada membina antara muka pengguna dan memudahkan pembangunan melalui pengikatan data komponen dan responsif. 2) Rangka kerja back-end seperti Express dan Django mengendalikan permintaan HTTP, operasi pangkalan data dan logik perniagaan, dan dijalankan di pelayan.

Vue.js disepadukan dengan tumpuan teknologi front-end untuk meningkatkan kecekapan pembangunan dan pengalaman pengguna. 1) Alat Pembinaan: Mengintegrasikan dengan Webpack dan Rollup untuk mencapai pembangunan modular. 2) Pengurusan Negeri: Bersepadu dengan VUEX untuk menguruskan status aplikasi yang kompleks. 3) Routing: Mengintegrasikan dengan Vuerouter untuk merealisasikan penghalaan aplikasi tunggal halaman. 4) Preprocessor CSS: Menyokong SASS dan kurang untuk meningkatkan kecekapan pembangunan gaya.

Netflix memilih React untuk membina antara muka penggunanya kerana reka bentuk komponen React dan mekanisme DOM maya dapat mengendalikan antara muka yang kompleks dan kemas kini yang kerap. 1) Reka bentuk berasaskan komponen membolehkan Netflix memecah antara muka ke dalam widget yang boleh diurus, meningkatkan kecekapan pembangunan dan pemeliharaan kod. 2) Mekanisme DOM maya memastikan kelancaran dan prestasi tinggi antara muka pengguna Netflix dengan meminimumkan operasi DOM.

Vue.js disukai oleh pemaju kerana mudah digunakan dan berkuasa. 1) Sistem pengikat data responsifnya secara automatik mengemas kini paparan. 2) Sistem komponen meningkatkan kebolehgunaan semula dan mengekalkan kod. 3) Ciri -ciri pengkomputeran dan pendengar meningkatkan kebolehbacaan dan prestasi kod. 4) Menggunakan vuedevtools dan memeriksa kesilapan konsol adalah teknik debugging biasa. 5) Pengoptimuman Prestasi termasuk penggunaan atribut utama, atribut yang dikira dan komponen-komponen Alive. 6) Amalan terbaik termasuk penamaan komponen yang jelas, penggunaan komponen fail tunggal dan penggunaan cangkuk kitaran hidup yang rasional.

Vue.js adalah rangka kerja JavaScript yang progresif yang sesuai untuk membina aplikasi front-end yang cekap dan boleh dipelihara. Ciri -ciri utamanya termasuk: 1. Pengikatan data responsif, 2. Pembangunan Komponen, 3. Dom maya. Melalui ciri -ciri ini, Vue.js memudahkan proses pembangunan, meningkatkan prestasi aplikasi dan mengekalkan, menjadikannya sangat popular dalam pembangunan web moden.

Vue.js dan bertindak balas masing -masing mempunyai kelebihan dan kekurangan mereka sendiri, dan pilihannya bergantung kepada keperluan projek dan keadaan pasukan. 1) vue.js sesuai untuk projek kecil dan pemula kerana kesederhanaan dan mudah digunakan; 2) React sesuai untuk projek besar dan UI yang kompleks kerana reka bentuk ekosistem dan komponennya yang kaya.

Vue.js meningkatkan pengalaman pengguna melalui pelbagai fungsi: 1. Sistem responsif menyedari maklum balas data masa nyata; 2. Pembangunan komponen meningkatkan kebolehgunaan semula kod; 3. Vuerouter menyediakan navigasi lancar; 4. Data dinamik mengikat dan animasi peralihan meningkatkan kesan interaksi; 5. Mekanisme pemprosesan ralat memastikan maklum balas pengguna; 6. Pengoptimuman prestasi dan amalan terbaik meningkatkan prestasi aplikasi.

Peranan vue.js dalam pembangunan web adalah bertindak sebagai rangka kerja JavaScript yang progresif yang memudahkan proses pembangunan dan meningkatkan kecekapan. 1) Ia membolehkan pemaju memberi tumpuan kepada logik perniagaan melalui pengikatan data yang responsif dan pembangunan komponen. 2) Prinsip kerja Vue.js bergantung kepada sistem responsif dan DOM maya untuk mengoptimumkan prestasi. 3) Dalam projek sebenar, adalah amalan biasa untuk menggunakan VUEX untuk menguruskan keadaan global dan mengoptimumkan respons data.


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

ZendStudio 13.5.1 Mac
Persekitaran pembangunan bersepadu PHP yang berkuasa

SublimeText3 versi Inggeris
Disyorkan: Versi Win, menyokong gesaan kod!

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

Penyesuai Pelayan SAP NetWeaver untuk Eclipse
Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.

Versi Mac WebStorm
Alat pembangunan JavaScript yang berguna
