Skip to content

Commit

Permalink
[MS-37] Fix 37 scheduler (#28)
Browse files Browse the repository at this point in the history
* test

* 문제상황 재현

* ss

* asdf

* version up

* deep
  • Loading branch information
Moon-DaeSeung authored Mar 25, 2024
1 parent 5ec6aba commit 3b01f9b
Show file tree
Hide file tree
Showing 51 changed files with 2,001 additions and 2,295 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/flitter/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@meursyphus/flitter",
"version": "0.0.8",
"version": "0.0.9",
"description": "A declarative, widget-based library built on SVG for simplifying data visualization with a Flutter-like syntax.",
"keywords": [
"flitter",
Expand Down
11 changes: 5 additions & 6 deletions packages/flitter/src/runApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,20 @@ export class AppRunner {
window: _window,
onResize: this.handleViewResize,
});
const renderDispatcher = new RenderFrameDispatcher();
const renderFrameDispatcher = new RenderFrameDispatcher();
const scheduler = new Scheduler({ renderFrameDispatcher });
const buildOwner = new BuildOwner({
onNeedVisualUpdate: () => renderDispatcher.dispatch(),
onNeedVisualUpdate: () => scheduler.ensureVisualUpdate(),
});

const renderOwner = new RenderOwner({
onNeedVisualUpdate: () => renderDispatcher.dispatch(),
onNeedVisualUpdate: () => scheduler.ensureVisualUpdate(),
renderContext: renderContext,
hitTestDispatcher: new HitTestDispatcher(),
});

const scheduler = new Scheduler();
scheduler.addPersistenceCallbacks(() => buildOwner.flushBuild());
scheduler.addPersistenceCallbacks(() => renderOwner.drawFrame());
renderDispatcher.setOnFrame(() => scheduler.schedule());
this.buildOwner = buildOwner;
this.renderOwner = renderOwner;
this.scheduler = scheduler;
Expand Down Expand Up @@ -124,7 +123,7 @@ export class AppRunner {
this.layout();
this.renderOwner.rearrangeDomOrder();
this.paint();
this.scheduler.consumePostCallbacks();
this.scheduler.flushPostCallbacks();
}

rebuild() {
Expand Down
6 changes: 0 additions & 6 deletions packages/flitter/src/scheduler/RenderFrameDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,10 @@ class RenderFrameDispatcher {
this.onFrame = () => callback();
}

// Actually we don't need to invoke browser to render because browser automatically render its own state periodically
// so Here we just call onFrame callback.
private idle = true;
dispatch() {
if (typeof window === "undefined") return;
if (!this.idle) return;
this.idle = false;
window.requestAnimationFrame(() => {
this.onFrame?.();
this.idle = true;
});
}
}
Expand Down
57 changes: 42 additions & 15 deletions packages/flitter/src/scheduler/Scheduler.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,73 @@
import { assert } from "src/utils";
import type RenderFrameDispatcher from "./RenderFrameDispatcher";

enum SchedulerPhase {
idle,
persistenceCallbacks,
postFrameCallbacks,
}

class Scheduler {
phase: SchedulerPhase;
private persistenceCallbacks: (() => void)[];
private postFrameCallbacks: (() => void)[];
constructor() {
private renderFrameDispatcher: RenderFrameDispatcher;
constructor({
renderFrameDispatcher,
}: {
renderFrameDispatcher: RenderFrameDispatcher;
}) {
this.phase = SchedulerPhase.idle;
this.persistenceCallbacks = [];
this.postFrameCallbacks = [];
this.renderFrameDispatcher = renderFrameDispatcher;

renderFrameDispatcher.setOnFrame(() => this.handleDrawFrame());
}

consumePostCallbacks() {
flushPostCallbacks() {
this.postFrameCallbacks.forEach(callback => {
callback();
});
this.postFrameCallbacks = [];
}

schedule() {
ensureVisualUpdate() {
switch (this.phase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
this.performSchedule();
this.schedule();
break;
case SchedulerPhase.persistenceCallbacks:
break;
}
}

private performSchedule() {
private hasScheduledFrame = false;
private schedule() {
if (this.hasScheduledFrame) return;
this.renderFrameDispatcher.dispatch();
this.hasScheduledFrame = true;
}

private handleDrawFrame() {
assert(
this.phase === SchedulerPhase.idle,
"Scheduler should be idle on beginning frame",
);
this.hasScheduledFrame = false;

this.phase = SchedulerPhase.persistenceCallbacks;
this.flushPersistenceCallbacks();
this.phase = SchedulerPhase.postFrameCallbacks;
this.flushPostCallbacks();
this.phase = SchedulerPhase.idle;
}

private flushPersistenceCallbacks() {
this.persistenceCallbacks.forEach(callback => {
callback();
});
this.phase = SchedulerPhase.postFrameCallbacks;
this.consumePostCallbacks();
this.postFrameCallbacks = [];
this.phase = SchedulerPhase.idle;
}

addPersistenceCallbacks(callback: () => void) {
Expand All @@ -46,10 +79,4 @@ class Scheduler {
}
}

enum SchedulerPhase {
idle,
persistenceCallbacks,
postFrameCallbacks,
}

export default Scheduler;
16 changes: 7 additions & 9 deletions packages/test/src/lib/diagram/Diagram.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
<script lang="ts">
import Widget from '@meursyphus/flitter-svelte';
import Diagram from './widget/Diagram';
import { project } from './fixture';
let container: HTMLElement;
import type { Project } from './type';
type Subscribe = (callback: (project: Project) => void) => () => void;
export let project: Project;
export let subscribe: Subscribe = () => () => {};
</script>

<div bind:this={container} class="w-full h-full border-l border-black bg-gray-200">
<Widget
widget={Diagram({ project: project, subscribe: () => () => {} })}
width="100%"
height="500px"
/>
</div>
<Widget widget={Diagram({ project, subscribe })} width="100%" height="100%" />

<style>
:global(svg text) {
Expand Down
Loading

0 comments on commit 3b01f9b

Please sign in to comment.