Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Globally async data object and global await feature #99

Open
SilentVoid13 opened this issue Mar 28, 2021 · 3 comments
Open

Globally async data object and global await feature #99

SilentVoid13 opened this issue Mar 28, 2021 · 3 comments
Labels
enhancement New feature or request

Comments

@SilentVoid13
Copy link

SilentVoid13 commented Mar 28, 2021

Is your feature request related to a problem? Please describe.

No, not really.

Describe the solution you'd like

I'd like to be able to await for all async functions in my data object without having to add the "await" keyword in front of each of them (maybe an option in the config).
In my case, I don't want users to ask themselves "is this function async or not?".

But the biggest benefit of this, and this is the reason of my feature request, is that I would like eta to be able to await for all the Promises of async functions globally (using something like Promise.all()) instead of individually, to speed things up.
Right now, eta is awaiting each async function one by one.
This means that if an async function takes 1 second, another 2 seconds and another 3 seconds, eta will take a total of 6 seconds instead of 3 (maximum possible time among the 3 functions) to render the templates.

Describe alternatives you've considered

Right now I'm using a kinda ugly hack to be able to await all for async functions in my data object: I'm basically adding the "await" keyword in front of every template variable.
It works fine but as I said before, since eta awaits each function one by one, this can be very slow.

let async_content = content.replace(new RegExp("it\.", "g"), "await it\.");
content = await Eta.renderAsync(async_content, context);

Additional context

Ideally, I'd like to be able to have something like this: multiple async functions (d1, d2, d3) in my data object and have eta do something like Promise.all in the background to speed things up.

function delay(ms: number) {
    return new Promise( resolve => setTimeout(resolve, ms) );
};

let d1 = delay(1000);
let d2 = delay(2000);
let d3 = delay(3000)

Promise.all([d1, d2, d3]).then((values) => {
    console.log("FINISHED !");
});

Among the popular templating js engines I tested (nunjucks, ejs, handlebars, ...), eta is probably the best templating engine to deal with async functions in the data object (kudos for that!).
Adding this feature would really make async functions a breeze to use.

Thanks for this excellent tool.

@shadowtime2000
Copy link
Collaborator

@SilentVoid13 So what you are requesting is to have Eta crawl the templates and find async functions to and automatically add them to a list? That seems kind of heavy and stuff and a little out of scope...

@SilentVoid13
Copy link
Author

SilentVoid13 commented Mar 28, 2021

@shadowtime2000 You're right maybe the global Promise.all() is a bit out of scope for this tool. I wouldn't mind implementing something like that myself but AFAIK there is no way to modify the way Eta deals with functions. I'd really like to be able to implement something like that while still using Eta though, do you have any suggestions on how I could achieve something like that ?

The option to await for all async functions by default seems like a valid use case though, and I don't think I'll be the only one using such a feature.

@SilentVoid13
Copy link
Author

Hey @shadowtime2000 any updates on this ?

I modified some stuff in eta to get it working on my side: added an alwaysAwait optional boolean option in the config and added the following code in the function compileScope in compile-string.ts:

[...]
if (type === 'r') {
  // raw

  if (config.alwaysAwait) {
    content = 'await ' + content;
  }

  if (config.filter) {
    content = 'E.filter(' + content + ')'
  }

  returnStr += 'tR+=' + content + '\n'
} else if (type === 'i') {
  // interpolate

  if (config.alwaysAwait) {
    content = 'await ' + content;
  }

  if (config.filter) {
    content = 'E.filter(' + content + ')'
  }

  if (config.autoEscape) {
    content = 'E.e(' + content + ')'
  }
  returnStr += 'tR+=' + content + '\n'
  // reference
}
[...]

Since await does nothing on variables / synchronous functions this seems like an "ok" solution.

Do you want me to make a PR for this or do you disagree with the idea of this option ? As I said I think this can be a valuable option for other users besides me.

@shadowtime2000 shadowtime2000 added the enhancement New feature or request label Apr 5, 2021
@shadowtime2000 shadowtime2000 linked a pull request Apr 5, 2021 that will close this issue
blutorange added a commit to blutorange/eta that referenced this issue Nov 28, 2021
blutorange added a commit to blutorange/eta that referenced this issue Nov 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants