Skip to content

Commit

Permalink
实现 watchEffect
Browse files Browse the repository at this point in the history
  • Loading branch information
jindy committed Oct 12, 2022
1 parent 3715784 commit 9ec93c1
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 14 deletions.
53 changes: 53 additions & 0 deletions packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { reactive } from "@guide-mini-vue/reactivity";
import { watchEffect } from "../src/apiWatch";
import { nextTick } from "../src/scheduler";
import { vi } from "vitest";

describe("api: watch", () => {
it("effect", async () => {
const state = reactive({ count: 0 });
let dummy;
watchEffect(() => {
dummy = state.count;
});
expect(dummy).toBe(0);

state.count++;
await nextTick();
expect(dummy).toBe(1);
});

it("stopping the watcher (effect)", async () => {
const state = reactive({ count: 0 });
let dummy;
const stop: any = watchEffect(() => {
dummy = state.count;
});
expect(dummy).toBe(0);

stop();
state.count++;
await nextTick();
// should not update
expect(dummy).toBe(0);
});

it("cleanup registration (effect)", async () => {
const state = reactive({ count: 0 });
const cleanup = vi.fn();
let dummy;
const stop: any = watchEffect((onCleanup) => {
onCleanup(cleanup);
dummy = state.count;
});
expect(dummy).toBe(0);

state.count++;
await nextTick();
expect(cleanup).toHaveBeenCalledTimes(1);
expect(dummy).toBe(1);

stop();
expect(cleanup).toHaveBeenCalledTimes(2);
});
});
26 changes: 26 additions & 0 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ReactiveEffect } from "../../reactivity/src/effect";
import { queuePreFlushCb } from "./scheduler";
export function watchEffect(source) {
function job() {
effect.run();
}
let cleanup;
const oncleanup = function (fn) {
cleanup = effect.onStop = () => {
fn();
};
};
function getter() {
if (cleanup) cleanup();
source(oncleanup);
}
const effect = new ReactiveEffect(getter, () => {
queuePreFlushCb(job);
});

effect.run();

return () => {
effect.stop();
};
}
41 changes: 28 additions & 13 deletions packages/runtime-core/src/scheduler.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
const queue: any[] = []
let isFlushPending = false
const p = Promise.resolve()
const queue: any[] = [];
const activePreFlushCbs: any[] = [];
let isFlushPending = false;
const p = Promise.resolve();
export function queueJobs(job) {
if (!queue.includes(job)) {
queue.push(job)
queue.push(job);
}
queueFlush()
queueFlush();
}

export function nextTick(fn) {
return fn ? p.then(fn) : p
export function nextTick(fn?) {
return fn ? p.then(fn) : p;
}

function queueFlush() {
if (isFlushPending) return
isFlushPending = true
nextTick(flushJobs)
if (isFlushPending) return;
isFlushPending = true;
nextTick(flushJobs);
}

function flushJobs() {
isFlushPending = false
let job
isFlushPending = false;

flushPrevFlushCbs();

let job;
while ((job = queue.shift())) {
job && job()
job && job();
}
}

function flushPrevFlushCbs() {
for (let i = 0; i < activePreFlushCbs.length; i++) {
activePreFlushCbs[i]();
}
}

export function queuePreFlushCb(cb) {
activePreFlushCbs.push(cb);
queueFlush();
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
"types": ["jest"], /* Specify type package names to be included without being referenced in a source file. */
"types": ["vitest/globals"], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
Expand Down

0 comments on commit 9ec93c1

Please sign in to comment.