Patterns for working with async JS

TW core is pretty seriously synchronous, I believe. But the existence of tm-http-request makes it clear that there are ways to deal with asynchronous functions as well. I will dig into that soon, but I imagine it is reasonably complex. I’m wondering if there are simple examples of wikitext (if possible) or JS code (more likely) that are async.

My use case is pretty simple. I’m generating SVG images in TW, which was surprisingly easy. But my final format has to be PNG or PDF. I have a simple function that generates PNGs from the SVG strings, but it uses new Image()...onLoad, which now makes it asynchronous. I haven’t tried using it yet, but it’s not clear to me how to use it to, say, render a tiddler with that PNG output. So are there good examples of similar things in the community?

Hi Scott, how to use async functions really depends on the use case, whether we are talking sync, rendering, saving, etc.

Do you want to render a tiddler as PNG and save that PNG in a tiddler or trigger a download? Or do you want to render it as PNG on demand and display it?

If you want to save it to a tiddler or initiate a download of the PNG file, then a widget message with a listener on the root widget is the recommended pattern. This means that the async code can run independent of the refresh cycle.

If you want to render it as PNG and display it on demand, then a widget that does so would be just fine even if it is async. The risk with async code is always that the calling widget might not exist when the async code completes due to the refresh cycle. In this case it makes sense that if the calling widget no longer exists, you would no longer want to display the image, so as long as the code fails gracefully in such situations that should be fine.

I am a bit pressed for time at present but hopefully that helps point you in the correct direction.

I hadn’t really thought it through, but the former would be find for my use-case. I was assuming the latter. I will try to follow your advice for that.

I’m not sure I follow on the render-it case, but I will play with it soon. The download will do all I need for the moment, and I think I can handle that.

Thank you once again!

Action widgets could be async, see those action widgets that calls its children action widgets (create tiddler action widget). Maybe you can write your functions as action widget, and let it call children when its async functions are done.

@Scott_Sauyet I confess I’m not following your intent re the PNGs and PDFs… but that’s likely not an issue for what I have to say.

Agreed. Take for example @EricShulman’s $action-timeout (i.e. settimeout) widget. Works like a charm: Search results for 'action-timeout' - Talk TW

And, of course, tm-http-request.

I’m generating political lawn signs using SVGs, which are much easier to manipulate programmatically than other image formats, at least for me. Because the rest of the Democratic Town Committee’s information was in a TW, I used that to generated the SVGs. But when I need to print them (soon!) I need to supply the sign company with a PDF or a PDF (maybe JPG too?).

I was just planning on scaling these up to the 24" x 18" lawn signs at 125 dpi and then downloading the resulting PNG tiddlers to send to them. But note I said “the PNG tiddlers”, as that was I was envisioning, some procedure/macro to turn the SVGs into PNGs. I simply didn’t have a handle on async rendering.

What @saqimtiaz pointed out was that if I only need to download the result, I can use download actions, and those don’t need to be synchronous. I haven’t tried this. Many other parts of the campaign need attention, and much of the time I was going to spend on it today was taken up by plumbing issues. Uggh!

Thanks, if I get back to this and don’t simply do some manual intervention, I’ll take a look.

Thank you both very much for your feedback!

1 Like