When working on a SolidJS project you might start seeing the following warning message in your JS console:
computations created outside a `createRoot` or `render` will never be disposed
There are some information available on this in SolidJS' Github repository issues. But after reading them I was still not quite sure what this was all about and whether my code was really doing something wrong.
I managed to track down where it came from and find a fix for it based on the documentation. So I'm providing the explanation and the solution for those Googling this warning message.
In essence this is a warning about a possibility of a memory leak due to a reactive computation being created without the proper context which would dispose of it when no longer needed.
A proper context is created a couple of different ways. Here are the ones I know about:
By using the render function.
By using the createRoot function. Under the hood render uses this.
By using the createContext function.
The first is by far the most common way, because each app has at least one render function call to get the whole show started.
So what makes the code go "out of context"?
Probably the most common way is via async calls. The context creation with its dependency tree happens only when the synchronous portion of the code finishes running. This includes all the export default function in your modules and the main app function.
But code that runs at a later time because of a setTimeout or by being in an async function will be outside of this context and any reactive computations created will not be tracked and might stick around without being garbage collected.
An example
Let's say you have a data input screen and have a Save button on it that makes an API call to your server to save the data. And you want to provide a feedback to the user whether the operation succeeded or not, with a nice HTML formatted message.
[msg,setMsg] = createSignal(<></>)
async function saveForm(){
...
setMsg(<p>Saving your data.<i>Please stand by...</i></p>)
const result=await callApi('updateUser',formData)
if(result.ok){
setMsg(<p>Your changes were <b>successfully</b> saved!</p> )
} else {
setMsg(<p>There was a problem saving your data! <br>Error: </p><pre>{result.error}</pre> )
}
}
...
<div>
...
<button onClick={saveForm} >Save</button>
{msg()}
</div>
This will produce the above mentioned warning when the API call returns an error, but not the other times. Why?
The reason for this is that SolidJS considers the code inserts inside JSX to be reactive, ie: need to be watched and re-evaluated. So inserting the error message from the API call creates a reactive computation.
The solution
I found the solution at the very end of the SolidJS doc. It's a special JSX modifier: /*#once*/
It can be used at the beginning of a curly brace expression and it tells the SolidJS compiler to explicitly not to make this a reactive expression. In other words: it will evaluated once and only once when the DOM nodes are created from the JSX.
In the above example here's how to use it:
setMsg(<p>There was a problem saving your data! <br>Error: </p><pre>{/*#once*/ result.error}</pre> )
After this there will be no more warning messages :)
In my case, I had an input and when that input changed I re-created an SVG drawing. Because the SVG creation was an expensive operation, I added a debounce in the createEffect function which ran when the input changed. debounce is a technique to defer the processing until the input stops changing for at least X amount of time. It involved running the SVG generation code inside the setTimeout function, thus being outside of the main context. Using the /*#once*/ modifier everywhere where I inserted an expression in the generated JSX has fixed the problem.
I'm working with Progress 10.1c
I have a class that contains both static and non-static methods.
The class is defined with USE-WIDGET-POOL. In the destructor I say "DELETE WIDGET-POOL".
I create an instance of my class, and call a method. The method itself uses one of the static methods of the class. So if I understand it correctly, I will now have the instance of my class in its own unnamed pool, and a separate unnamed widget pool for the static members of the class.
So far so good. But I'm busy debugging and I'm making changes to the code. I recompile and run my test again. Now my non-static members work, but all the static members come from the older version of my class, that is still stored in the pool for static members, which is scoped to the session. In other words, the "DELETE WIDGET-POOL" in my destructor deleted the pool for the instance of the class, but the pool for the static members is still there.
The only way I can get it to load the new version of my class is to log off my session, and log on again. This is quite a mission in our environment. Every time I make a change, I have to stop and start my development environment.
I tried to walk the list of objects in my session, but could not find what I'm looking for. There's a good chance I'm starting at the wrong object, or I'm missing some knowledge of pools and objects in Progress.
Is there any way for me to target that unnamed pool and delete the static "instance" of my class, without destroying my session every time?
This turned out to be doable with very little coding. I can use the statement DELETE OBJECT THIS-OBJECT to delete the instance executing that statement. So if it's in a static method, it is the static instance that gets deleted.
METHOD STATIC VOID Reload () :
DELETE OBJECT THIS-OBJECT.
END METHOD.
So now when I have a new version of the class, I just use MyClass:Reload(). No need to end my session.
Thanks to Tim Kuehn for pointing me in the right direction with his suggestion of using a static method to delete the named widget-pool.
I have created this example to demonstrate how I got it to work. Below is a simple class with 3 static methods:
/* File : rtt/cls/demo.cls */
USING Progress.Lang.*.
ROUTINE-LEVEL ON ERROR UNDO, THROW.
CLASS rtt.cls.demo USE-WIDGET-POOL :
METHOD STATIC CHARACTER SayHello() :
RETURN "Good-bye".
END METHOD.
METHOD STATIC VOID ShowMessage() :
MESSAGE "This is the message." VIEW-AS ALERT-BOX.
END METHOD.
METHOD STATIC VOID Reload() :
DELETE OBJECT this-object.
END METHOD.
END CLASS.
I don't know how other people's environments are set up, but in my environment I have to log on to our system to be able to compile and run programs, in other words, I have an active session.
So I compile the file:
COMPILE VALUE(SEARCH("rtt/cls/demo.cls")) SAVE.
And then I run the following bit in Procedure Editor to test it:
USING rtt.cls.*.
demo:ShowMessage().
MESSAGE demo:SayHello().
When I run this, I get a message box that says "This is the message.", followed by a message box that says "Good-bye". Exactly as one would expect.
But there's a bug, it's supposed to say "Hello", not "Good-Bye", so I edit my class (I'm only showing the two methods I'm changing:
METHOD STATIC CHARACTER SayHello() :
RETURN "Hello".
END METHOD.
METHOD STATIC VOID ShowMessage() :
MESSAGE "That was the message." VIEW-AS ALERT-BOX.
END METHOD.
I save my changes, compile it as before, and I run the test again. What messages do you expect to see? I expect to see "This is the message." and "Good-bye", same as before. That's logical, because there is a hidden widget-pool in my current session, and it has an instance of my class loaded (from my first test). It will keep on using this instance until the instance or the pool is destroyed. So I shut down my development environment, log off and then log on again to start up a new session. So far everything is working exactly as expected.
Now I run my test again, and sure enough, I get my new version: the messages are "That was the message" and "Hello".
But now I'm told to add an exclamation after the word "Hello". so I change it:
METHOD STATIC CHARACTER SayHello() :
RETURN "Hello!".
END METHOD.
I save it and compile it. When I run the test, obviously I will get the older version that says "Hello" without the exclamation. I have to restart my session again before my changes become active. I really don't want to do that again. So I change my test as follows:
USING rtt.cls.*.
demo:Reload().
demo:ShowMessage().
MESSAGE demo:SayHello().
I run it and voilĂ , I get my latest changes. I change the message from "That was the message" to "It works!". I save, compile and run my test. What do I see? I see "It works!". No more restarting my session between edits. My solution works perfectly for me.
I tried all sorts of stuff, but I cannot get it to generate the error "Cannot Reference THIS-OBJECT or SUPER from a static member (15071)".
Static class elements last for the duration of the ABL session, and the only way to 'unload' them is to have a database connection go down (ie, the db server is shut down). This unloads everything, clears the client code, and leaves you in the 4GL editor.
Beyond that, the only other possible way is to create a named widget pool for the static class, then call a (static) method to delete that. I have no idea if this would work or not.
"Static members that are scoped to the class type. This unnamed widget pool is implicitly
deleted only when the ABL session in which the widget pool is created terminates."
http://documentation.progress.com/output/OpenEdge102b/pdfs/dvoop/dvoop.pdf
page 5-9
In this case make you something wrong. You should use the static members only for methods or properties, which are realy static and must be not deleted or reinitialised when is deleted the instance of class.
when you will use it anyway, you should define your own static widget-pool with name and any static dynamic objects create in this widget-pool. then can you in Reload() write:
METHOD STATIC VOID Reload () :
DELETE WIDGET-POOL XYZ.
CREATE WIDGET-POOL XYZ.
END METHOD.
other way is to use a singelton class, where are defined this 'static' objects. then anytime, when you will, you can delete the instance of this singelton and make some new fresh.
I have been working on something that checks an MySQL Database to check something - however the program stops responding because it is constantly checking the database. Is it possible to have it wait a few seconds to recheck the database? I have tried sleep() but it is giving a strange error:
A call to PInvoke function
'Game!WindowsApplication1.Form1::Sleep' has unbalanced the
stack. This is likely because the managed PInvoke signature
does not match the
unmanaged target signature. Check that the calling convention
and parameters of the
PInvoke signature match the target unmanaged signature.
I have been looking into this for quite a while and i am in a predicament. I do need the MySQL databases to be checked very often. I tried making a web browser refresh before checking it again - but it started to lag the application.
Code:
function updateit()
' SQL Code goes here, it succeeds.
updateit() ' Update it again.
return true
end
updateit()
Your code example shows a recursive function with no base case. The result of that is always a stack overflow (an uncatchable exception in .Net).
Don't call your updateit() function from within the function itself. Instead, just write a loop to call it over and over.
Try doing your checks from a separate thread. Try dragging a BackgroundWorker onto your form and putting your check in that to make your program more responsive. I've never seen that error before though. Is it System.Threading.Thread.Sleep() or something specific to VB?
Looking at your code it looks like you've got infinite recursion. That will cause a stackoverflow... try
while(true)
'SQL code
end
Let suppose I create a class, and in this class I declare a method that will run a loop.
My question is what will be behavior of loop, if I dispose the object of class and condition of loop is yet true - will loop execute or terminate.
Usually the object (variable) is managed by a single thread. So you may not be able dispose of easily because the thread is still running in the loop. If you mult-thread and you call in a method that modifies this variable (your object) on the a different thread you may crash your program. If your loop in a UI thread which has a message pump (sta thread) and you call a method directly from another thread then you app will crash as this is not allowed.
All in all what do you want to do ? Mark Byers's condition "The code keeps running" is the most possiable outcome of this I think. But you have a bug either way - don't attempt to drive a car and then just jump out of it without stopping.
I wrote a loader class that has a tries property that indicates how many times to retry loading a url if an error code is returned. For instance with Twitter, the loader would retry loading a method call if a fail whale is returned, since the next call would probably return success.
I specify the many errors that can be dispatched with string constants, so there's XMLLoaderError.IO, XMLLoaderError.SECURITY, etc. I'm having trouble thinking of a name for the error dispatched if the number of tries exceeds the tries property. At first, I thought XMLLoaderError.TRIES_EXCEEDED, but I'm certain there's something better out there. I considered XMLLoaderError.TIMEOUT, but timeout is more of a single load error. Or I can be clever and use XMLLoaderError.TRYOUT (jk) Any ideas?
Since your other errors indicate the type/genre of error that occurred - ie. "SECURITY" or "IO" - and these are within the XMLLoader context, why not just name it TRY? XMLLoaderError.TRY makes sense to me - or actually, XMLLoaderError.RETRIES probably makes even more sense!