Marc:
No problem on the response time... I knew you would eventually get around to catch up on this item...
I guess I'm still a little confused as to why the completefunc "...only function properly sporadically.". I have never encountered an issue with it, but would like to hear the troubles you have encountered/seen/heard. And, as you know, I wrap SPServices today in $.Deferred() calls and have have not seen any issues - both completefunc processing and Promise methods execute properly and achieve the expected results.
The only issue I can think of is if xData data (the XMLDocument object) is manipulated in one callback which would impact the expectation of the next callback (ex. .done() would change it... completefunc() would now possibly not get a the real XMLDocument ... but even if this is what you refer to, it has no association to the async setting being true/false).
Taking Promises out of the discussion (I think all you did there was returned the jQuery .ajax() return value), the change you made will cause all existing (let's call it "legacy" :) ) code to perform in synchronous mode. As you know, in the browser, all synchronous calls block the UI and thus user experience will be hurt by this change for anyone who has build significant applications around SPServices. I, for one, cannot just drop this new version into an existing environment anymore because all existing calls would suddenly lock up the UI/browser. I would have to refactor everything to use .promises if I wanted calls to be done in async=true. I have several customizations that do "background" calls for data (ex. to refresh cached items - used with MVC frameworks) and then act on those values without the user's knowledge... This change would almost certainly introduce a "stutter" affect on the page or cause it to be come momentarily unresponsive. Also, in cases were multiple pieces of data need to be retrieved from different Lists/Libraries in order to join them together would now take a 2-fold or more hit on performance as all of those calls would be done serially. Below is an example of a piece of code I lifted from a project I worked on that would see a big performance/UI hit...
Now, Back to support of Promises: I agree with you that defining a completefunc in addition to using Promises is silly... they both accomplish the same thing but in different ways (execute code later, after call returns from the server). But, completefunc is still a valid input parameter and its setting should not have (IMHO) have a impact to the user's setting of async. And, as you probably very well know: users will use both. Take for example the jQuery Ajax methods... They all now - I think - return a Promise to the caller (with the exception of .load()), but also continue to support a callback method, as they did in the pass. Setting the callback and/or using the Deferred method (.then(), .always(), .done(), etc...) has no impact on the synchronous setting of the server call.
I also agree that creating/using a Deferred with async=false is again silly and defeats the purpose, but as long as your default setting support what is "right", it falls back on the user to know just exactly what they are doing. I understand you are trying to protect the end user, but given you existing user base, you may actually be doing more harm than good (again :) IMHO).
Paul.
(ps. yes... I'm probably not a good candidate to represent the majority of SPServices users... many are just interested in small changes and look for copy-and-paste code... but... your library has enabled me to make some very powerful application. :) )
Example of UI and performance hit:
The code below would be executed serially and in synchronous mode under v2013.01... UI would lock up and time to complete would probably increase more than 2-fold.
No problem on the response time... I knew you would eventually get around to catch up on this item...
I guess I'm still a little confused as to why the completefunc "...only function properly sporadically.". I have never encountered an issue with it, but would like to hear the troubles you have encountered/seen/heard. And, as you know, I wrap SPServices today in $.Deferred() calls and have have not seen any issues - both completefunc processing and Promise methods execute properly and achieve the expected results.
The only issue I can think of is if xData data (the XMLDocument object) is manipulated in one callback which would impact the expectation of the next callback (ex. .done() would change it... completefunc() would now possibly not get a the real XMLDocument ... but even if this is what you refer to, it has no association to the async setting being true/false).
Taking Promises out of the discussion (I think all you did there was returned the jQuery .ajax() return value), the change you made will cause all existing (let's call it "legacy" :) ) code to perform in synchronous mode. As you know, in the browser, all synchronous calls block the UI and thus user experience will be hurt by this change for anyone who has build significant applications around SPServices. I, for one, cannot just drop this new version into an existing environment anymore because all existing calls would suddenly lock up the UI/browser. I would have to refactor everything to use .promises if I wanted calls to be done in async=true. I have several customizations that do "background" calls for data (ex. to refresh cached items - used with MVC frameworks) and then act on those values without the user's knowledge... This change would almost certainly introduce a "stutter" affect on the page or cause it to be come momentarily unresponsive. Also, in cases were multiple pieces of data need to be retrieved from different Lists/Libraries in order to join them together would now take a 2-fold or more hit on performance as all of those calls would be done serially. Below is an example of a piece of code I lifted from a project I worked on that would see a big performance/UI hit...
Now, Back to support of Promises: I agree with you that defining a completefunc in addition to using Promises is silly... they both accomplish the same thing but in different ways (execute code later, after call returns from the server). But, completefunc is still a valid input parameter and its setting should not have (IMHO) have a impact to the user's setting of async. And, as you probably very well know: users will use both. Take for example the jQuery Ajax methods... They all now - I think - return a Promise to the caller (with the exception of .load()), but also continue to support a callback method, as they did in the pass. Setting the callback and/or using the Deferred method (.then(), .always(), .done(), etc...) has no impact on the synchronous setting of the server call.
I also agree that creating/using a Deferred with async=false is again silly and defeats the purpose, but as long as your default setting support what is "right", it falls back on the user to know just exactly what they are doing. I understand you are trying to protect the end user, but given you existing user base, you may actually be doing more harm than good (again :) IMHO).
Paul.
(ps. yes... I'm probably not a good candidate to represent the majority of SPServices users... many are just interested in small changes and look for copy-and-paste code... but... your library has enabled me to make some very powerful application. :) )
Example of UI and performance hit:
The code below would be executed serially and in synchronous mode under v2013.01... UI would lock up and time to complete would probably increase more than 2-fold.
$.When(
// Get Document info.
$.Deferred(function(dfd){
$().SPServices({
operation: "GetListItems",
async: true,
listName: "Documents",
CAMLQuery: "<Query><Where><Eq><FieldRef Name='DocNumber'/><Value Type='Text'>" +
k + "</Value></Eq></Where></Query>",
CAMLRowLimit: 0,
completefunc: function(xData, Status) {
dfd.resolveWith(xData, [xData, Status]);
}
});
}),
// Get Doc. Issues
$.Deferred(function(dfd){
$().SPServices({
operation: "GetListItems",
async: true,
listName: "Baselined Documents",
CAMLQuery: "<Query><Where><Eq><FieldRef Name='DocNumber'/><Value Type='Text'>" +
k + "</Value></Eq></Where></Query>",
CAMLRowLimit: 0,
completefunc: function(xData, Status) {
dfd.resolveWith(xData, [xData, Status]);
}
});
}),
// Get Author info
$.Deferred(function(dfd){
$().SPServices({
operation: 'GetUserProfileByName',
AccountName: userAcctName,
async: true,
completefunc: function (xData, Status){
dfd.resolveWith(xData, [xData, Status]);
}//end:completefunc()
});
})
)
.done(function(DocInfo, DocIssues, DocAuthor){
// Build Doc./User profile UI
})