From 84705fc463a685062474972ff4c298e6aa92e621 Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Wed, 6 Jun 2018 09:53:45 -0400 Subject: [PATCH 1/4] replace new Promise(r => r()) with Promise.resolve Promise.resolve is a Promise convenience method that creates a promise resolved to a given argument like creating a promise with a function that immediately calls the resolve function with the given value. --- src/blocks/scratch3_sound.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index 4c637e71a..a599b314c 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -231,9 +231,7 @@ class Scratch3SoundBlocks { util.target.audioPlayer.setEffect(effect, soundState.effects[effect]); // Yield until the next tick. - return new Promise(resolve => { - resolve(); - }); + return Promise.resolve(); } _syncEffectsForTarget (target) { @@ -284,9 +282,7 @@ class Scratch3SoundBlocks { util.target.audioPlayer.setVolume(util.target.volume); // Yield until the next tick. - return new Promise(resolve => { - resolve(); - }); + return Promise.resolve(); } getVolume (args, util) { From 9311a274d5c2711d530b05a26e5d23f362167d64 Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Wed, 6 Jun 2018 10:13:29 -0400 Subject: [PATCH 2/4] add BlockUtility.yieldTick --- src/engine/block-utility.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/engine/block-utility.js b/src/engine/block-utility.js index 2026c0f0d..b456d02fa 100644 --- a/src/engine/block-utility.js +++ b/src/engine/block-utility.js @@ -57,6 +57,13 @@ class BlockUtility { this.thread.status = Thread.STATUS_YIELD; } + /** + * Set the thread to yield until the next tick of the runtime. + */ + yieldTick () { + this.thread.status = Thread.STATUS_YIELD_TICK; + } + /** * Start a branch in the current block. * @param {number} branchNum Which branch to step to (i.e., 1, 2). From 0a006dc9811e9b7008189169d2e4ce45de29b5fa Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Wed, 6 Jun 2018 09:57:53 -0400 Subject: [PATCH 3/4] add Runtime.isWaitingThread Add a Runtime Thread helper to check if a thread is in a state where it will not change at least until next frame. This includes any state where the thread is done, as that will not change either. --- src/engine/runtime.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/engine/runtime.js b/src/engine/runtime.js index ab38955e4..3acfe4bbf 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -1017,6 +1017,19 @@ class Runtime extends EventEmitter { this.threads.indexOf(thread) > -1); } + /** + * Return whether a thread is waiting for more information or done. + * @param {?Thread} thread Thread object to check. + * @return {boolean} True if the thread is waiting + */ + isWaitingThread (thread) { + return ( + thread.status === Thread.STATUS_PROMISE_WAIT || + thread.status === Thread.STATUS_YIELD_TICK || + !this.isActiveThread(thread) + ); + } + /** * Toggle a script. * @param {!string} topBlockId ID of block that starts the script. From d161251a9b6acc45a36f5991b91ba80abd9d22d1 Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Wed, 6 Jun 2018 09:59:38 -0400 Subject: [PATCH 4/4] yield a thread loop or tick in event_broadcastandwait - yield a thread loop or tick in looks_switchbackdroptoandwait If all threads broadcastAndWait is watching are "waiting" for a future frame, yield until the next tick so event_broadcastandwait also defers to a future frame. --- src/blocks/scratch3_event.js | 12 +++++++++++- src/blocks/scratch3_looks.js | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/blocks/scratch3_event.js b/src/blocks/scratch3_event.js index ba496a172..6d4eaca8a 100644 --- a/src/blocks/scratch3_event.js +++ b/src/blocks/scratch3_event.js @@ -100,7 +100,17 @@ class Scratch3EventBlocks { const instance = this; const waiting = util.stackFrame.startedThreads.some(thread => instance.runtime.isActiveThread(thread)); if (waiting) { - util.yield(); + // If all threads are waiting for the next tick or later yield + // for a tick as well. Otherwise yield until the next loop of + // the threads. + if ( + util.stackFrame.startedThreads + .every(thread => instance.runtime.isWaitingThread(thread)) + ) { + util.yieldTick(); + } else { + util.yield(); + } } } } diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index 4a7994a4a..21599f251 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -409,7 +409,17 @@ class Scratch3LooksBlocks { const instance = this; const waiting = util.stackFrame.startedThreads.some(thread => instance.runtime.isActiveThread(thread)); if (waiting) { - util.yield(); + // If all threads are waiting for the next tick or later yield + // for a tick as well. Otherwise yield until the next loop of + // the threads. + if ( + util.stackFrame.startedThreads + .every(thread => instance.runtime.isWaitingThread(thread)) + ) { + util.yieldTick(); + } else { + util.yield(); + } } }