I have been learning client-side object model and came across the method executeQueryAsync
. I found there are quite a few ways to call this method. Some of the one I found were these:
var context = new SP.ClientContext.get_current();
// Option 1
context.executeQueryAsync(
function(sender, args){ },
function(sender, args){ }
);
// Option 2
context.executeQueryAsync(
Function.createDelegate(this, _onSucceed),
Function.createDelegate(this, _onFail)
);
// Option 3
context.executeQueryAsync(
Function.createDelegate(this, this._onSucceed),
Function.createDelegate(this, this._onFail)
);
// Option 4
context.executeQueryAsync(_onSucceed, _onFail);
Which of this way is the most optimal/preferred one? Also what does the statement Function.createDelegate
do? The documentation for this function seems to be very cryptic for me.
First I would say there is no 'optimal way' as these all just behave somewhat differently... Second, I would add this isn't so much a SharePoint or executeQueryAsync specific thing as it is a JS thing in general...
Next we need to understand that
executeQueryAsync
expects two functions as arguments: the first is a function to perform ifexecuteQueryAsync
succeeds, the second is a function to perform if the method encounters an error. These functions are passed parameters (fromexecuteQueryAsync
, not from your JS) representing the sending object as well as an arguments object that can have some data (args.get_message()
andargs.get_stackTrace()
are common in the case of a failed call)In your 'Option 1' example,
executeQueryAsync
is given two anonymous functions, you won't be able to re-use them anywhere, but if the behavior is simple this may be sufficient.In Option 2 you use the
createDelegate
method to give the success and failure callbacks a context -- this speaks to scoping within JavaScript; if you need to reference a variable that is only accessible in the function that callsexecuteQueryAsync
, you'll need to use this sort of pattern so thatthis
within the callback references the function that calledexecuteQueryAsync
instead of the success or failure function that you're now in. You can think of creating a delegate as the calling function calling on some other function, but saying 'I want that function to be able to see what I can see no matter where it's located at within the code.' This may all seem a bit arcane, but such is scoping within JavaScript... You could completely circumvent the need for doing this by referencing variables at higher scope levels (say inside of a function that contains the calling method as well as the success and failure methods)Option 3 is just like Option 2, except it just specifies that the
_onSucceed
or_onFail
functions should be the ones that are contained within the calling objectOption4 is just like Option 1, except that you've named the functions (and that they are available within the current scope) and are calling them by name.
I usually use something like option 2, or option 4 -- but I hope you can see that it really just depends on how you're trying to structure your code.
EDIT: In response to a comment about
Function.createDelagate()
-- It seems to just be a helper in an ASP.NET script resource; it does nothing other than callingapply()
(which is the standard JS way of doing this -- see MDN documentation here). It might also provide some backward compatibility somewhere within ASP.NET, but I'm not really sure!Here is the code for the function from a script resource file in my SP environment:
And as a bonus, I was thinking about how I use
executeQueryAsync
and I realized that I actually use it more often like option 1, with a promise pattern using jQuery deferreds like this:Then you can do things a little less-spaghetti-like, such as:
Just in case anyone cares! :)