Blog - Rencore

SharePoint JavaScript Context Development Part 6 – jQuery vs SharePoint

Written by Waldek Mastykarz | Jan 27, 2015 12:37:49 AM

This blog is part of the blog series SharePoint JavaScript Context Development

Parts 3&4 are linked. Please read in order.

Last week I wrote about how people just really like to use jQuery for everything. If they need to select elements on the page, they revert to jQuery because it is easy. This is a heavy point in the right direction blog post. I do not go into detail for usage, but I will update and blog links to usage examples as I create them.

However, if you are working in the SharePoint client context you have almost the whole thing implemented for you. There are some differences but on the whole we have all the tools we require for everyday development, and in some cases the SharePoint versions have better implementations.

On top of this, SharePoint methods are all built with SharePoint in mind. Not being a normal website there are many UI components that have very specific code requirements (The most notorious, of course, is MDS see previous parts for more on this).

So it lends to the question, which do you use? The answer is either just SharePoint or both. Never just use jQuery, and I will come back to this point after directly comparing jQuery to SharePoint below.

In jQuery we use the core jQuery(selector).<method> to achieve these things. In SharePoint, we have the equivalent of this with an implementation called mQuery.

Note: To load mQuery on premises or an older/customised 365 tenant you call it with the mquery SOD key. It is already registered on the page and is MDS compatible.

mQuery (m$) Utilities

Don’t be fooled mQuery isn’t jQuery. It may look like it it may even perform some of the same actions. However it is very light, but perhaps this is all you need.

The base helper methods of mQuery are:

throttle, extend, makeArray, isDefined, isNotNull, isUndefined, isNull, isUndefinedOrNull, isDefinedAndNotNull, isString, isBoolean, isFunction, isArray, isNode, isElement, isMQueryResultSet, isNumber, isObject, isEmptyObject, isReady, ready, contains, proxy, support, every, filter, forEach, indexOf, lastIndexOf, map, some, data, removeData, hasData, callBaseMethod, getBaseMethod, getBaseType, getInterfaces, getName, implementsInterface, inheritsFrom, initializeBase, isImplementedBy, isInstanceOfType, registerClass, registerInterface, resolveInheritance and registerEnum.

These methods, on the whole, are very recognisable. However, we can see there are some that are for working with classes in JavaScript. These extend beyond the ones found in Type or supplied in other places of SharePoint. So if you wish to use classes and inheritance then these can be very useful.

The main difference here is that methods such as makeArray, ready and forEach are designed for SharePoint types, so will work properly with the SharePoint context allowing you to work with iterators and MDS respectively.

 Selectors, Comparisons, Modifers and Events

The DOM manipulation elements of mQuery are also very similar to jQuery:

length, constructor, append, bind, unbind, trigger, contains, detach, find, closest, offset, one, filter, not, parent, offsetParent, parents, parentsUntil, position, attr, addClass, removeClass, css, remove, children, empty, first, data, removeData, EventuallyDetect_DOMNodeRemovedFromDocument, blur, change, click, dblclick, error, focus, focusin, focusout, keydown, keypress, keyup, load, mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup, resize, scroll, select, submit, unload and map.

Here we can see that we can do almost everything we would normally do with jQuery. Some useful wrapper methods in jQuery are not included. However most of what we would do in jQuery is intact.

The benefits, of using mQuery, are clear. It is a much smaller library and already loaded in 365 tenants. If it covers what you require there is no need to load in anything else. However mQuery does not contains sizzle.js which is the selector engine used by jQuery, and it does not include some manipulation methods such as after.

These downsides mean that you cannot pass mQuery into your other libraries such as angular.js as jQuery. However, there are libraries that will work with it. So if performance is a key factor, investigating using this exclusively will benefit you.

Promises and Deferred

jQuery have implemented a partial version of this in recent times. SharePoint has had it for quite a while, but it just isn’t documented.

What I am talking about is the Task Carousel. Task Carousel is a core element of SharePoint JavaScript and allows us to track, and run methods asynchronously in the client context.

Task Carousel is a heavily patented technology and underused. The Cancellable Command Application Programming Interface Framework as it is also known allows cooperative multitasking for synchronous and asynchronous operations based on a command timing sequence.

Task Carousel takes the idea of Promises to the whole new level. You firstly create a command block and add to the task engine, so it can run and monitor the command.

To provide a perfect example, the patent for the Task Carousel shows us an example implementation. (US Patent US20130055266).

We can see from the below code we can perform tasks in chunks, or perform a complete task in a single go. Allowing chunks of processing means that long running processes can be kept track of, and more importantly it allows the end user to be notified of the progress.

// Create and execute the task. For example, a browser page can include a
// button that can be activated to start a task running.
// The button node is passed to the task engine.
function RunLongTest(button) {
       var longTask;
       var state = new TestTaskState(container);
       longTask = new SP.Utilities.Task(button, 0,
           new SP.Utilities.CommandBlock(state, TestTask, FinishTestTask),
           CancelTestTask,
           LongTestTask, ProgressMeter);
       if (longTask != null)
           longTask.StartTask();
   }
// This is the function that actually executes the task
// under control of the API.
// The task is very simple, it just counts.
function TestTask(state, PauseFunc) {
       var longIncr = 0.01;
       var longGoal = 9999.0;
       var counter = state.counter;
       var container = state.container;
       for (counter += longIncr; counter <> counter += longIncr) {
           // give control back if requested.
           if (PauseFunc())
               break;
       }
       // Maintain state to pick up where processing left off.
       state.counter = counter;
       // Tell the system the state.
       return counter / longGoal;
   }
// This function will be called when return > 1
// from TestTask( ). change the button text back.
function FinishTestTask(element, state) {
       element.innerText = ″Long Running″;
   }
// This function is called when upon hitting the 0.5 second mark.
// We change the text of the button that was hit to start
// the task to say “Working . . .”
function LongTestTask(element, state) {
       element.innerText = ″Working...″;
   }
// If the task is cancelled change the button text back
// to “Long Running”.
function CancelTestTask(element, state, type) {
       element.innerText = ″Long Running″;
       return true; // Really cancelled
   }
// This is just a data block to maintain state for the
// operation if it's interrupted.
function TestTaskState(container) {
       this.counter = 0.0;
       this.container = container;
   }
// A progress meter that display in an element called countercontainer.
var progressContainer = null;
 
function ProgressMeter(percentDone, timeElapsed) {
   // Have to have somewhere to show progress.
   if (progressContainer == null)
       progressContainer = document.getElementById(″countercontainer″);
   progressContainer.style.display = ″″;
   // Meter just shows percent done in text.
   progressContainer.innerText =
       (Math.round(percentDone * 100)).toString() + ′ % ′;
   if (percentDone >= 1.0) {
       progressContainer.style.display = ″none″;
       progressContainer = null;
   }
}

Asynchronous JavaScript and XML (AJAX)

jQuery has a very robust set of Ajax methods. But not to be outdone, SharePoint has one better.

The SP.RequestExecutor (MSDN SP.RequestExecutor). This library is not loaded by default, and you do require a call to SOD (See previous part so on how to achieve this) but it includes a couple of extra tricks up its sleeve.

Usually in SharePoint we are doing either cross-domain calls or we are performing post backs. Firstly SP.RequestExecutor allows for cross-domain via CORS (JSONP is insecure) allowing it to interact with any CORS enabled endpoint.

The second post back. SharePoint includes a security procedure called a canary check. The Canary Check is a unique key passed to the client to prevent spoofing from other sources. SP.RequestExecutor knows about this and will handle this for you without having to think about it. This is handled through the formDigestHandlingEnabled property of the Request Executor object.

The other bonuses to this are that it will also make use of the App Web Proxy when required. It works well with iFrames, and it handles Ajax request queuing internally so there will be no chance of threads locking up.

This does mean the library is much larger than jQuery.Ajax portion, but if you do not need even 10% of jQuery you are not saving anything by loading this instead and handling the above caveats yourself.

SP.RequestExecutor is a class, so you will need to instantiate it before usage. Also to make use of a proxy, it has the option to take a “via” in its constructor:

var requestExecutor = new SP.RequestExecutor(String url, Undefined viaUrl);

Once instantiated we can then use it pretty much as we would jQuery.ajax.

requestExecutor.executeAsync({
                url: someUrl,
                method: "GET",
                headers: { "Accept": "application/json; odata=verbose" },
                success: successCallback,
                error: errorCallback
});

Pros and Cons

For 99% of projects, we can use the out of the box methods and save ourselves page load time. However, many developers know jQuery and will be using jQuery when developing apps.

So what shall we do? Decide.

Decide what is best for your project that you are working on. If you think the page load time will not be affected by an extra download of 55KB of data. I will be clear; 55KB of data is not a lot. However, it does add a request for the file, and the file is not MDS compatible, which does in all impact the whole perceived performance of a page. Whereas an already loaded library or a smaller library will reduce this impact. Using my recent blog post “Loading a JavaScript library from a CDN” you can automagically wrap jQuery with code that makes it MDS compatible, so this may not be a problem.

However, let me also be clear, jQuery methods are not written with SharePoint in mind. Many methods will not work properly with the optimizations put into place or extra security requirements while in the context of SharePoint. jQuery.ready is one of these, it has no idea if a page is loaded. In Some cases it will work, and then on others it will not. This is because it has no idea that the page is controlled by an asynchronous delta loader, that loads page data after the page has loaded. mQuery, however, uses the SharePoint methods to load, or you can use a version of the one I posted earlier in this series.

Another big point is the Ajax vs. Request Executor. For me, even if I were going to use jQuery I would use SP.RequestExecutor. It is far more robust and much more powerful.

Conclusion

SharePoint is badly documented for client-side development; I do not blame anyone who runs to jQuery in order to do things that are out of the box. However, I want to help drive the commitment to using out of the box even in code. You do not write or load libraries when they are included already in C#, you should not in JavaScript. It is best practice to use what is there before running to use what isn’t.

Please leave your thoughts and example requests in the comments; I am eager to gauge your feedback.

Next time I will talk about debugging scripts that have been loaded by SOD, and other tricks which will help reduce development time.

Merken