Key Points to Know When Using SP.SOD.executeFunc and SP.SOD.executeOrDelayUntilScriptLoaded

So there I was trying to get SharePoint’s script on demand (SOD) working correctly and I thought I had it all figured out.  I ran across a post called SharePoint Scripts on Demand which covers the topic very thoroughly, but there is some behavior between executeOrDelayUntilScriptLoaded and executeFunc that I don’t think is really clearly called out. That lack of understanding led to some major frustrations, and I would like to alleviate you of that fate.  So here’s the deal:

The executeOrDelayUntilScriptLoaded function accepts a function delegate and a script key.  If the script associated with the key is loaded, then the function delegate executes immediately.  If the script is not loaded, the function delegate is queued up and will execute if and when the script associated with the script key is ever loaded.  Understand, however, that the script may never be loaded so that queued method delegate may never fire.  I think most people tend to understand how this function operates fairly well.

The executeFunc function, however, does not work like I would expect it to work.  This function accepts a script key, a JavaScript AJAX class type name (normally this is just null), and a function.  So it’s very similar to the executeOrDelayUntilScriptLoaded function, but the key different is that if the script associated with the script key is not loaded, executeFunc loads the script and executes the delegate method.  This is fine and good and exactly what I would expect.  What I believe to be odd is that if the script associated with the script key is already loaded, then executeFunc does absolutely NOTHING.  I assumed it would run the delegate method if the script was already loaded, but that is apparently not the case.

What does this mean?  Well, in my case I was trying to load the scripts on demand when a user clicked a ribbon button and then execute a method in my script.  My initial attempt at this just used the executeFunc method.  Unfortunately, that meant that my code worked the first time the button was clicked, but never again.  To get it to work, I had to use both methods in conjunction with one another as follows:

  { ... code ... }, "myScript.js");
executeFunc("myScript.js", null, null);

The call to executeOrDelayUntilScriptLoaded contains the code I actually want to run.  The first time through, the function gets queued up because my script is not loaded.  The next line contains the executeFunc method that ensures my script is loaded.  Notice that the delegate method is null.  Once the script is loaded, my button click code executes because that queued function gets fired.  The second time through, my button click code executes immediately because the executeOrDelayUntilScriptLoaded sees that my script is already loaded, and the executeFunc line does nothing because the script is already loaded.  So it takes two methods to get the job done, but it seems to work.