JS sleep/timeout function (custom widget)?

114 views
Skip to first unread message

Hubert

unread,
May 6, 2020, 6:08:33 AM5/6/20
to TiddlyWiki
Hello,

Similar to what was discussed here, is there a JavaScript custom widget with a single timeout function that would make it possible to run a sleep/timeout/delay for a number of miliseconds as provided through its parameter?

My use case would be to only have the single timeout function in the widget, so the widget would only make sense if it was placed before another action widget whose actions are to be delayed. It would not do anything meaningful on its own, other than freezing the browser a few seconds (which, I know, sounds risky in itself).

There's some discussion on StackOverflow and elsewhere advising against such solutions, unless in very specific use cases. Freezing anything on purpose does not sound as the safest thing to do. I was wondering if someone knowledgeable in JS could share their thoughts on the best approach to achieve this with little to no risk.

Many thanks,
Hubert

Jed Carty

unread,
May 6, 2020, 6:41:22 AM5/6/20
to TiddlyWiki
Somewhere I have some experiments with something like this. A much safer alternative is to have a background daemon running that emits some event every so often and use that as a clock, then your widget counts pulses (or waits until after a specific time) and then acts.

So you could have the background daemon emit a pulse event every second, then you have an action widget that will count a certain number of pulses before before running the action widgets that it contains.

I hope that makes sense. I have run into a few cases where this would be useful for me in the last few days, but I am not sure how long it will be before I will have the time to make it.

Alternately you could go the easier route and just use a setTimeout in the widget that waits however long you want before running the code. That is how the background daemon would work anyway, the only reason to not use that is that the time would only be accessible inside the widget instead of a globally available clock.

Hubert

unread,
May 6, 2020, 8:42:26 AM5/6/20
to TiddlyWiki
Thanks Jed.

I've actually made some tests with setTimeout in a custom JavaScript widget and have realised that setTimeout only delays a function that it is calling.

What this means is that the setTimeout method will have no effect on any subsequent actions that may be defined in any separate action widgets that are stacked below it, because any functions defined there will simply be out of scope for the function defined in our current timeout widget.

Please correct me if I'm wrong, but from what I've understood, all action widgets are self contained/sandboxed in this respect by design (due to security?) or maybe it's just due to JS multi-threading, I have no idea. Either way, it appears that setTimeout will not just magically delay JS operations globally, not least in any subsequent action widgets.

Thanks,
Hubert

Jed Carty

unread,
May 6, 2020, 3:02:04 PM5/6/20
to TiddlyWiki
In the same way that a button widget can have child widgets whose behaviour is affected by the button widget, you could make a widget that calls other widgets, or affects widgets contained inside it.

You could make an action widget that takes a string of action widgets as a parameter and a delay and then runs the widgets after the delay.

The layout would be like this:

<$button>
WHEE!!!
<$magic-delay-widget
actions="""Some list of action widgets here""
delay="1 million years"
/>
</$button>

the fastest way to do this would be to modify the button widget to take a delay input and then put the setTimeout around everything inside the click handler.
There are probably nicer ways to do it, but that would work and should be relatively straight forward.

then it would be a normal button with an extra parameter like this, the actions passed as the actions attribute or listed inside the button tags shouldn't make any difference doing it that way:

<$magicbutton
delay='10 microseconds'
actions='lots of action widgets in this list!'
>
MAGIC!
</$magicbutton>!

Hubert

unread,
May 7, 2020, 4:59:02 AM5/7/20
to TiddlyWiki
That sounds great, thanks Jed. I'm only just beginning to learn JavaScript but this is some important info.

I'm sure I'll come up with some solutions eventually and find new problems as I go :)

Thanks,
Hubert

Jed Carty

unread,
May 7, 2020, 7:41:26 AM5/7/20
to TiddlyWiki
I got bored and needed a break from my other work, so I made the widget I described: https://ooktech-tw.gitlab.io/plugins/delayactions/

Hubert

unread,
May 7, 2020, 8:01:31 AM5/7/20
to TiddlyWiki
Jed, thank you!!! This is fantastic. It works as advertised, great work!

Many thanks,
Hubert

Hubert

unread,
May 7, 2020, 8:11:33 AM5/7/20
to TiddlyWiki
Jed, may I suggest that you announce this plugin to the wider group. I think it's brilliant and maybe more people will find it useful as well.

I think that also Saq and Jeremy hinted at selectively delaying actions during their hangout that was recently published here. I think what was said was that sometimes some changes are not captured by the subsequent action widgets because they fired before TW was able to render changes made by the previous action widgets. So, I feel like there could be a wider need for your widget :)

Thanks again,
Hubert

TonyM

unread,
May 7, 2020, 9:06:59 AM5/7/20
to TiddlyWiki
Could those in the thread explain to a broader audience what such a function would do for us and or a use case?

thanks
Tony

Hubert

unread,
May 7, 2020, 9:35:08 AM5/7/20
to TiddlyWiki
Tony,

Here's one totally non-representative example:
  1. When I log a new running/cycling workout, I select some options and then click a "Log" button.
  2. This button initiates a sequence of actions (a stack of action widgets), the last of which is a fancy animated notification.
  3. However, when I'm on mobile, my fancy animated notification "Workout logged" is not animated, because my phone is still overwhelmed after running all the previous actions.
  4. So what I've done now using Jed's plugin is wrap my notify action widget like below. Now the notification still shows nicely on mobile, with animation and all, because the 2 second delay was more than enough for the processing power to "recover" and for my phone to render the video (CSS) effect properly:
<$action-one/>
<$action-two/>
<$action-delay delay="2">
<$action-sendmessage $message="tm-notify" $param="_notify_logged"/> // Delayed action
</$action-delay>
 
There are many other examples where you can spread out actions over time, we're no longer confined to firing everything this instant. One (probably not a useful one) example could be to show an alert and then close it 5 seconds later.

But again, it all depends on the problem you're trying to solve.

Hope this helps.

Regards,
Hubert
Reply all
Reply to author
Forward
0 new messages