I am having trouble zeroing in on this bug, but something happened when I upgraded from 3.13 to 3.15. In some (but not all) templates where I use the result of a helper in a let block, the helper will be rerendered infinitely.
{{#let (data-fetch-task @theThing) as |data|}}
{{await data}}
{{/let}}
If I don’t do anything with data, it’s fine. As soon as I try to use data for anything, it blows up. Specifically, I have examples of troubles with both promises and concurrency tasks. They’re very baked into my frameworks so it’s hard to break them out one at a time. I’ll have to work on that.
I’ve seen examples of how this has happened in the past due to bugs such as this one:
https://github.com/emberjs/ember.js/issues/14351
I also read about helpers that modify arguments to the helper thereby causing a rerender. But I’m pretty sure I checked that well and that’s not the problem.
The browser will slow to a crawl, and if I put console.log(‘hi’) statement in the helper’s compute function, I’ll see thousands of ‘hi’s. So I know it’s getting called over and over
I know this isn’t a very complete question, but I’m in a bind now and it’s the best I can scrape up.
Is there anything that can happen in the octanifying of my app that could make this happen?
EDIT --- MORE INFO
This is a bare-bones version of my helper that is being called over and over. "field" is an EmberObject that holds model information - in this case the available values for a field.
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
export default class AvailableValsHelper extends Helper {
@service store;
compute([field]){
console.log("started");
return field.availableValues(this.store);
}
}
availableValues is
(store) => store.findAll('product-types');
The logic is right. If I put it in a computed property it works fine.
The helper is used in a template like this:
{{#let (available-vals @field) as |opts|}}
{{log opts}}
{{/let}}
If I leave out the log, it works fine, but it isn't actually being called, so ... so what :-/
I've tried making the helper a function instead of a class and I've tried changing the scope of "store" to the component with the same result. I've gone all the way up the stack to make sure the @'s and this's, etc. are right too in case it was an issue with name / scope confusion. If it was swallowing an error then I don't know why it would work as a cp on the component - apparently that's another mode of failure.
And this is only one helper. I have another that returns a task and it's doing the same thing. I never opted into any Octane behaviors though I've used almost all the design patterns: angle bracket syntax, native classes, async/await, etc. I was on 3.13 and when I went to 3.15 this popped up. Like I said, if I define the helper output as a cp on the component, then it works, so that's the "workaround." I can't help but feel that I've stumbled upon some weird mode of failure or I've got my config jacked up where some wrappers are doing things "the octane way" and others "the old way."
One time I saw a different trace in the console that was from "store" and it said maximum stack level exceeded during a call to findAll. It literally caused me to do a hard reset on my machine, so I wasn't able to save it. I should have taken a picture with my phone. There was a line about "trackable." I don't remember what it said. But looking at it made me wonder if because the reference to "store" is a closure, if it was trying to track a change to a value that had no context of value. I'm not really terribly familiar with how all that works, but I thought it was weird to see that call when I thought all I was doing was a pretty straightforward method application.