Rumah > Artikel > hujung hadapan web > Bagaimana untuk melaksanakan pengiraan dalam sistem responsif Vue3
Pertama sekali, mari kita semak secara ringkas:
Inti sistem responsif ialah WeakMap --- Peta --- Tetapkan struktur data.
Kunci WeakMap ialah objek asal dan nilainya ialah Peta responsif. Dengan cara ini, apabila objek dimusnahkan, Peta yang sepadan juga akan dimusnahkan.
Kunci Peta ialah setiap atribut objek dan nilainya ialah satu set fungsi kesan yang bergantung pada atribut objek ini. Kemudian gunakan kaedah dapatkan objek proksi Proksi untuk mengumpul fungsi kesan yang bergantung pada sifat objek ke dalam Set yang sepadan dengan kunci. Ia juga perlu untuk membuat proksi kaedah set objek dan memanggil semua fungsi kesan kunci apabila mengubah suai sifat objek.
Dalam artikel lepas, kami melaksanakan sistem responsif yang agak lengkap berdasarkan idea ini, dan kemudian terus melaksanakan pengiraan hari ini.
Pertama sekali, kami membina semula kod sebelumnya dan memisahkan pelaksanaan pengumpulan kebergantungan dan mencetuskan fungsi kebergantungan ke dalam fungsi trek dan pencetus:
Logik masih menambah kesan pada Set yang sepadan dan mencetuskan pelaksanaan fungsi kesan dalam Set yang sepadan, tetapi ia lebih jelas apabila diabstraksikan.
Kemudian teruskan melaksanakan pengiraan.
Penggunaan pengiraan lebih kurang seperti ini:
const value = computed(() => { return obj.a + obj.b; });
Bandingkan kesan:
rreeePerbezaannya hanya satu lebih banyak nilai pulangan.
Jadi kami melaksanakan pengiraan berdasarkan kesan seperti ini:
effect(() => { console.log(obj.a); });
Sudah tentu, kesan semasa tidak mempunyai nilai pulangan, jadi kami perlu menambahnya:
Hanya rekod nilai pulangan dan kembalikan berdasarkan pelaksanaan fungsi kesan sebelumnya.
Kini dikira boleh mengembalikan nilai yang dikira:
Tetapi kini data diluluskan dan semua kesan dilaksanakan di sini seperti dikira tidak perlu dilaksanakan semula setiap kali, ia hanya perlu dilaksanakan selepas data berubah.
Jadi, kami menambah pilihan malas untuk mengawal kesan bukan untuk dilaksanakan serta-merta, tetapi untuk mengembalikan fungsi dan membiarkan pengguna melaksanakannya sendiri.
Kemudian apabila menggunakan kesan dalam pengiraan, tambahkan pilihan malas supaya fungsi kesan tidak dilaksanakan tetapi kembali.
Buat objek dalam pengiraan dan panggil fungsi ini untuk mendapatkan nilai terkini apabila nilai get dicetuskan:
Mari kita uji:
Anda boleh melihat bahawa atribut nilai nilai pulangan yang dikira kini boleh mendapatkan nilai yang dikira dan obj.a telah diubah suai. Selepas itu, fungsi pengiraan akan dilaksanakan semula, dan nilai baharu akan diperoleh apabila nilai diperoleh semula.
Ia hanya melakukan satu lagi pengiraan Ini kerana semua fungsi kesan akan dilaksanakan apabila obj.a berubah:
Dalam. dengan cara ini, setiap kali data berubah, fungsi yang dikira akan dilaksanakan semula untuk mengira nilai terkini.
Ini tidak perlu sama ada fungsi kesan dilaksanakan atau tidak juga harus dikawal. Jadi kita perlu menambah fungsi penjadualan padanya:
boleh menyokong penghantaran dalam fungsi panggil balik schduler, dan kemudian apabila melaksanakan kesan, jika terdapat penjadual , serahkan kepadanya Biarkan pengguna menjadualkannya sendiri, jika tidak, fungsi kesan akan dilaksanakan.
Dengan cara ini pengguna boleh mengawal pelaksanaan fungsi kesan:
Kemudian cuba kod sekali lagi:
Seperti yang anda lihat, selepas obj.a berubah, fungsi kesan tidak dilaksanakan untuk mengira semula, kerana kami menambah sheduler untuk menjadualkannya sendiri. Ini mengelakkan keperluan untuk melaksanakan fungsi yang dikira serta-merta selepas data berubah, dan anda boleh mengawal pelaksanaan sendiri.
Sekarang ada masalah lain, res.value mesti dikira setiap kali ia diakses:
能不能加个缓存呢?只有数据变了才需要计算,否则直接拿之前计算的值。
当然是可以的,加个标记就行:
scheduler 被调用的时候就说明数据变了,这时候 dirty 设置为 true,然后取 value 的时候就重新计算,之后再改为 false,下次取 value 就直接拿计算好的值了。
我们测试下:
我们访问 computed 值的 value 属性时,第一次会重新计算,后面就直接拿计算好的值了。
修改它依赖的数据后,再次访问 value 属性会再次重新计算,然后后面再访问就又会直接拿计算好的值了。
至此,我们完成了 computed 的功能。
但现在的 computed 实现还有一个问题,比如这样一段代码:
let res = computed(() => { return obj.a + obj.b; }); effect(() => { console.log(res.value); });
我们在一个 effect 函数里用到了 computed 值,按理说 obj.a 变了,那 computed 的值也会变,应该触发所有的 effect 函数。
但实际上并没有:
这是为什么呢?
这是因为返回的 computed 值并不是一个响应式的对象,需要把它变为响应式的,也就是 get 的时候 track 收集依赖,set 的时候触发依赖的执行:
我们再试一下:
现在 computed 值变了就能触发依赖它的 effect 了。至此,我们的 computed 就很完善了。
完整代码如下:
const data = { a: 1, b: 2 } let activeEffect const effectStack = []; function effect(fn, options = {}) { const effectFn = () => { cleanup(effectFn) activeEffect = effectFn effectStack.push(effectFn); const res = fn() effectStack.pop() activeEffect = effectStack[effectStack.length - 1] return res } effectFn.deps = [] effectFn.options = options; if (!options.lazy) { effectFn() } return effectFn } function computed(fn) { let value let dirty = true const effectFn = effect(fn, { lazy: true, scheduler(fn) { if(!dirty) { dirty = true trigger(obj, 'value'); } } }); const obj = { get value() { if (dirty) { value = effectFn() dirty = false } track(obj, 'value'); console.log(obj); return value } } return obj } function cleanup(effectFn) { for (let i = 0; i < effectFn.deps.length; i++) { const deps = effectFn.deps[i] deps.delete(effectFn) } effectFn.deps.length = 0 } const reactiveMap = new WeakMap() const obj = new Proxy(data, { get(targetObj, key) { track(targetObj, key); return targetObj[key] }, set(targetObj, key, newVal) { targetObj[key] = newVal trigger(targetObj, key) } }) function track(targetObj, key) { let depsMap = reactiveMap.get(targetObj) if (!depsMap) { reactiveMap.set(targetObj, (depsMap = new Map())) } let deps = depsMap.get(key) if (!deps) { depsMap.set(key, (deps = new Set())) } deps.add(activeEffect) activeEffect.deps.push(deps); } function trigger(targetObj, key) { const depsMap = reactiveMap.get(targetObj) if (!depsMap) return const effects = depsMap.get(key) const effectsToRun = new Set(effects) effectsToRun.forEach(effectFn => { if(effectFn.options.scheduler) { effectFn.options.scheduler(effectFn) } else { effectFn() } }) }
Atas ialah kandungan terperinci Bagaimana untuk melaksanakan pengiraan dalam sistem responsif Vue3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!