-
Bug
-
Resolution: Fixed
-
Major
-
3.6
-
MOODLE_36_STABLE
-
MOODLE_34_STABLE, MOODLE_35_STABLE
-
MDL-64181-master -
Failed to pre-fetch template error still occurs when rendering a tree of templates from javascript twice at the same time.
MDL-64164 is not a fix, it's just a work-around for one use-case (core/modal).
History of these issues.
When mustache was added, it was supported for php and javascript. The javascript version uses http://github.com/janl/mustache.js. When the renderer encounters a tag that requires another template, it calls a function which has to return the HTML for the template. It does not handle getting a promise - the function must return the HTML immediately. To do this we added a "pre-render" step which parses the HTML, finds all tags that include another template, generates a promise for each one to load the template via AJAX, waits for all the promises to resolve and then renders the template (and once the template is loaded it recursively does the same thing).
The first version did not handle recursive templates rendered in javascript, it would hang for ever waiting for it's chain of promises to return.
Process 1: wait for A raw -> wait for B raw -> wait for C raw -> wait for A raw (loop continues forever).
We added a fix for this, but the fix is not perfect and when the same template is rendered twice in javascript at the same time and the template includes another template, the first call to render will wait correctly, but the second one will not wait for all the included templates to be ready.
Process 1: wait for A raw -> wait for B raw -> render A
Process 2: wait for A raw -> render A (did not wait for B!)
To fix this we record a unique ID in each outer call to render() so we do not wait for ourselves, but we do wait if the template we need is being loaded by another different call to render().
Not recursive:
Process 1: wait for A raw -> wait for B raw -> render A
Process 2: wait for A raw -> wait for B raw -> render A
Recursive:
Process 1: wait for A raw -> wait for B raw -> (do not wait for A because we are already waiting for it) -> render A
Process 2: wait for A and all its dependencies-> render A