Library functions registered with registerPreloadMethod
keep calling _incrementPreload
after preloading is done.
#5677
Labels
registerPreloadMethod
keep calling _incrementPreload
after preloading is done.
#5677
Most appropriate sub-area of p5.js?
p5.js version
1.4.0
Web browser and version
chrome 100.0.4896.127
Operating System
Windows 10
Steps to reproduce this
Steps:
setup()
repeatedly in an infinite loop.window.myLibFunction
was initiallyundefined
, but later gets assigned a value.Snippet:
myLib.js -- a package that contains a named object
myLib
, and registers object methods with p5sketch.js -- a p5 sketch that calls the preload-registered function
myLib.myLibFunction()
insetup()
rather than inpreload()
complete example on p5 web editor
Issue:
I've been trying to fix some bugs with registering preloads in ml5.js, which is a p5.js library. It turns out that one of the issues that we are having is actually a bug in p5 itself! I dug pretty deep into the source code to figure things out so I can explain exactly what the problem is.
The issue occurs when calling
registerPreloadMethod
with a property of a custom object (ie. the library) rather than with p5 as the source object. When a custom object is used, the method gets wrapped in a function that calls_incrementPreload
, but it never gets unwrapped. Things will work ok if the method is called inpreload()
. But if it is called insetup()
then it will increment the_preloadCount
up to1
when the function starts and decrement it back to0
when the function resolves, which then triggers p5 callingsetup()
again...and again...in an infinite loop.The looped function chain is
myLib.myLibFunction
=>_decrementPreload
=>_runIfPreloadsAreDone
=>_setup()
=>myLib.myLibFunction
.Here are the relevant lines of code:
p5.js/src/core/main.js
Line 267 in 8d7b608
obj
here is themyLib
object. So this code is settingmyLib.myLibFunction
to the version which calls_incrementPreload
. That's all good, until:p5.js/src/core/main.js
Lines 325 to 334 in 196d3af
The code to reset the function back to its previous version ignores
obj
as the source.context
is the context ofp5
which is thewindow
f
is the name of the method'myLibFunction'
this._preloadMethods
is a dictionary of method names to source objects, so:this._preloadMethods[f]
ismyLib
this._preloadMethods[f][f]
ismyLib.myLibFunction
In short, the assignment on line 329 is equivalent to
window.myLibFunction
=myLib.myLibFunction
. Its setsmyLibFunction
on the window, even though it wasn't a global variable before. It does not setmyLib.myLibFunction
back to its original version.Fix?
The "unwrap" code block needs to be modified to support the case where the method is not attached to p5.
There needs to be a reference to the original version of the method. I believe
this._preloadMethods[f]
would point to the same object instance asmyLib
so it would contain the overwritten function. It seems likethis._registeredPreloadMethods
holds the necessary reference to the original, based on:p5.js/src/core/main.js
Lines 266 to 267 in 196d3af
Edit: it looks like this has been a known issue since 2015!
The text was updated successfully, but these errors were encountered: