David Sehnal 7 年 前
コミット
50ee781d18

+ 21 - 12
src/examples/computation.ts

@@ -12,6 +12,10 @@ async function test() {
     console.log(r);
 }
 
+function delay(ms: number) {
+    return new Promise(r => setTimeout(r, ms));
+}
+
 function messageTree(root: Progress.Node, prefix = ''): string {
     if (!root.children.length) return `${prefix}${root.progress.message}`;
 
@@ -20,25 +24,30 @@ function messageTree(root: Progress.Node, prefix = ''): string {
     return `${prefix}${root.progress.message}\n${subTree.join('\n')}`;
 }
 
-function createTask<T>(delay: number, r: T): Task<T> {
+function createTask<T>(delayMs: number, r: T): Task<T> {
     return Task.create('delayed', async ctx => {
-        await new Promise(r => setTimeout(r, delay));
-        if (ctx.requiresUpdate) await ctx.update({ message: 'hello from delayed...' });
+        ctx.updateProgress('Processing delayed... ' + r);
+        await delay(delayMs);
+        if (ctx.needsYield) await ctx.yield({ message: 'hello from delayed... ' + r });
         return r;
     });
 }
 
 async function testObs() {
     const t = Task.create('test o', async ctx => {
-        await new Promise(r => setTimeout(r, 250));
-        if (ctx.requiresUpdate) await ctx.update({ message: 'hi! 1' });
-        await new Promise(r => setTimeout(r, 125));
-        if (ctx.requiresUpdate) await ctx.update({ message: 'hi! 2' });
-        await new Promise(r => setTimeout(r, 250));
-        if (ctx.requiresUpdate) await ctx.update({ message: 'hi! 3' });
-
-        const r = await ctx.runChild({ message: 'Running child!' }, createTask(250, 100));
-        if (ctx.requiresUpdate) await ctx.update({ message: 'Almost done...' });
+        await delay(250);
+        if (ctx.needsYield) await ctx.yield({ message: 'hi! 1' });
+        await delay(125);
+        if (ctx.needsYield) await ctx.yield({ message: 'hi! 2' });
+        await delay(250);
+        if (ctx.needsYield) await ctx.yield('hi! 3');
+
+        ctx.updateProgress('Running children...');
+        const c1 = ctx.runChild(createTask(250, 1));
+        const c2 = ctx.runChild(createTask(500, 2));
+        const c3 = ctx.runChild(createTask(750, 3));
+        const r = await c1 + await c2 + await c3;
+        if (ctx.needsYield) await ctx.yield({ message: 'Almost done...' });
         return r + 1;
     });
     const r = await Run(t, p => console.log(messageTree(p.root)), 250);

+ 19 - 9
src/mol-task/execution/observable.ts

@@ -116,20 +116,26 @@ class ObservableRuntimeContext implements RuntimeContext {
         }
     }
 
-    get requiresUpdate(): boolean {
+    get needsYield(): boolean {
         this.checkAborted();
         return now() - this.info.lastUpdated > this.info.updateRateMs;
     }
 
-    private setProgress(update: Partial<RuntimeContext.ProgressUpdate>) {
+    private setProgress(update?: string | Partial<RuntimeContext.ProgressUpdate>) {
         this.checkAborted();
 
+        if (!update) return;
+
         const progress = this.node.progress;
-        if (typeof update.canAbort !== 'undefined') progress.canAbort = update.canAbort;
-        if (typeof update.current !== 'undefined') progress.current = update.current;
-        if (typeof update.isIndeterminate !== 'undefined') progress.isIndeterminate = update.isIndeterminate;
-        if (typeof update.max !== 'undefined') progress.max = update.max;
-        if (typeof update.message !== 'undefined') progress.message = update.message;
+        if (typeof update === 'string') {
+            progress.message = update;
+        } else {
+            if (typeof update.canAbort !== 'undefined') progress.canAbort = update.canAbort;
+            if (typeof update.current !== 'undefined') progress.current = update.current;
+            if (typeof update.isIndeterminate !== 'undefined') progress.isIndeterminate = update.isIndeterminate;
+            if (typeof update.max !== 'undefined') progress.max = update.max;
+            if (typeof update.message !== 'undefined') progress.message = update.message;
+        }
     }
 
     private resume = () => {
@@ -137,7 +143,11 @@ class ObservableRuntimeContext implements RuntimeContext {
         this.lastScheduledTime = now();
     }
 
-    update(progress: Partial<RuntimeContext.ProgressUpdate>): Promise<void> {
+    updateProgress(progress?: string | Partial<RuntimeContext.ProgressUpdate>) {
+        this.setProgress(progress);
+    }
+
+    yield(progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<void> {
         this.isExecuting = false;
         this.setProgress(progress);
         this.info.lastUpdated = now();
@@ -146,7 +156,7 @@ class ObservableRuntimeContext implements RuntimeContext {
         return ImmediateScheduler.last(this.resume);
     }
 
-    async runChild<T>(progress: Partial<RuntimeContext.ProgressUpdate>, task: Task<T>): Promise<T> {
+    async runChild<T>(task: Task<T>, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> {
         this.setProgress(progress);
         const node: Progress.Node = { progress: defaultProgress(this.info.taskId, task), children: [] };
         const children = this.node.children as Progress.Node[];

+ 5 - 4
src/mol-task/execution/runtime-context.ts

@@ -7,12 +7,13 @@
 import Task from '../task'
 
 interface RuntimeContext {
-    readonly requiresUpdate: boolean,
+    readonly needsYield: boolean,
+    updateProgress(progress: string | Partial<RuntimeContext.ProgressUpdate>): void,
     // Idiomatic usage:
-    // if (ctx.requiresUpdate) await ctx.update({ ... });
-    update(progress: Partial<RuntimeContext.ProgressUpdate>): Promise<void>,
+    // if (ctx.needsYield) await ctx.yield({ ... });
+    yield(progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<void>,
     // Force the user to pass the progress so that the progress tree can be kept in a "good state".
-    runChild<T>(progress: Partial<RuntimeContext.ProgressUpdate>, task: Task<T>): Promise<T>
+    runChild<T>(task: Task<T>, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T>
 }
 
 namespace RuntimeContext {

+ 4 - 3
src/mol-task/execution/synchronous.ts

@@ -10,9 +10,10 @@ import RuntimeContext from './runtime-context'
 const voidPromise = Promise.resolve(void 0);
 
 class SynchronousRuntimeContext implements RuntimeContext {
-    requiresUpdate: boolean = false;
-    update(progress: Partial<RuntimeContext.ProgressUpdate>): Promise<void> { return voidPromise; }
-    runChild<T>(progress: Partial<RuntimeContext.ProgressUpdate>, task: Task<T>): Promise<T> { return ExecuteSynchronous(task); }
+    needsYield: boolean = false;
+    updateProgress(progress: string | Partial<RuntimeContext.ProgressUpdate>): void { }
+    yield(progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<void> { return voidPromise; }
+    runChild<T>(task: Task<T>, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> { return ExecuteSynchronous(task); }
 }
 
 const SyncRuntimeInstance = new SynchronousRuntimeContext();