The second workflow action goes as expected, with synchronous events happening first then the asynchronous one happening after.
@sudsy pinging you because I don’t want to clutter that other thread. Any thoughts on this?
P.S: I used your template on this one.
P.P.S: It’s supposed to 404, not trying to actually fetch anything.
i am trying to turn an image URL into a base64 image. I need this to occur before any other code in my plugin. currently, this runs asynchronously or at least it seems that way. Do i construct this in a different manner to hold up the code?
Ah, I faced that challenge right when I started making plugins, and I used that exact same script to work with that. Nostalgic
The solution I used back then was rather convoluted, it involved promises, capturing their “resolve” function into an instance.data.resolve function, resolving them at the last workflow action etc etc not pretty.
Try placing the entire function inside the context.async and awaiting all asynchronous operations. It’s not going to be fast or easy to do this change.
A much faster way but more cumbersome to the end user (possibly not even usable depending on the whole flow) would be to make the image loading a single workflow action, then it publishes the base64 in a state and triggers an event when it’s ready.
Another option would be to find another way to do the conversion with a code that you can better adapt to the “context.async” structure.
Keep in mind that context.async will cache the request done, so if you run it multiple times it will always bring the same image, faking that the subsequent requests were done.
Yeah, but think where would they get that base64 from… if it’s a server side action, they can just use file or image:converted to base64 Bubble operator.
If it’s a client side action it would maybe require an extra step, which is the server side action I just mentioned.
Yep! I have something ready to be shared about it, including, it’s an excerpt from my upcoming plugin making training material (you can join its waitlist if you want to be super powerful ).
In short, you use traditional code. Here it goes:
…Alternatively, if you’re working on the browser, which means a client side action, you won’t use the context.async function anymore. It’s available there, but it will break your flow. Here’s how you do in the browser:
// declaring it
const requestToGetPlainText = async (fileUrl) => {
let response = await fetch(fileUrl);
let plainText = await response.text();
instance.publishState("attained_text", plainText)
instance.triggerEvent("Text is available")
}
// calling it
let myPlainTextValue = requestToGetPlainText("https://example.com/myFile.csv")
Noticed that I not only published the value to a state, but also triggered an event?
Because that’s how we can make sure that everything from this workflow is finished and will be available in the next workflow when we use async operations in the client side.
In other words: By triggering an event in the end of the async function.
Then, the next workflow that is ran under the event “Text available”, will have access to whatever text value you attained from this web request.
Here almost a year later, but I did notice that context.async seems to be working now.
Only bumping this incase someone did want to use it; I’d recommend declaring a function within the larger run_server function:
function(properties, context) {
//...
function myAsyncFunction() {
return context.async(async callback => {
try {
let return_var = "never set in code";
// ...
// do your processing here
// ...
return_var = "something_here"; // update return var
callback(null, return_var);
}
catch (err) {
callback(err);
}
});
}
//...
}
The reason for this is so that you can control when to call the function. The traditional method @vini_brito mentions is probably still good to, but I went with context.async because I wanted to be sure it would work on Bubble’s backend workflows.