SharePoint Framework performance optimization list


This is a guide created by me and a colleague of mine, Xiyuan Zeng from Spanish point, both with extensive SharePoint experience. It is basically our experience shared in a list. It is the recommended performance document for the two teams I am currently working with.

SharePoint Framewrok performance optimization

Reduce the HTTPS calls that your SPFx web part does to SharePoint and external apis

HTTPS is the biggest enemy when we deal with web services in the cloud. Every HTTPS call introduces delay in your web part because of latency. To reduce the delay we could:

  • Minimize the HTTPS calls and the data size transferred
  • Use localStorage to simulate perceived performance when possible (but be aware it has limitations). Invalidate the localStorage to fetch latest data after the first call and change the react state later if needed.
  • Use sessiontStorage to cache repeating content pulled from HTTPS (but be aware it has limitations)
  • Load data from a web service in advance if it has to be loaded later, but has to be fast (edge case) e.g. authentication via ADAL.js, user profile, user preference
  • Use service workers when possible (nice to have)
  • Use load on-demand for large data set, e.g. show more, arrow in slider, to reduce initial data transfer

SharePoint Search and Caml Queries considerations

  • Use .filter or .where clause to limit the number of items to be retrieved
  • Consider Path and/or ContentTypeId as default to have criteria in querytext
  • Use code/schema provisioned content type to have a fixed content type id which can be used to find all children content types
  • Use row limit if possible to limit the number of items to be retrieved
  • Use paging to retrieve additional items when needed
  • Use .select to limit the data entities to be retrieved
  • Never pull all the items from a list or library
  • Use search query over CAML for optimal performance
  • Avoid using site level, cross list CAML query
  • Avoid client side filtering and sorting, build them into query instead
  • Be aware of the data freshness
            ○ Search crawler index data at certain interval, data is not up to date
            ○ CAML query data directly, always returning the latest data

Examples using pnp js:

    OK SharePoint SEARCH QUERY
     
    pnp.sp.search(<SearchQuery>{
        Querytext: "path:https://YOUR_SITE.sharepoint.com/sites/site1/lists/list1 AND text1", // HAS DETAILED WHERE CLAUSE
        RowLimit: 10, // HAS ROW LIMIT
        SelectProperties: ["Title", "SPWebUrl", "projectID"],  // HAS SELECT STATEMENT
    }).then((r: SearchResults) => {
        console.log(r.ElapsedTime);
        console.log(r.RowCount);
        console.log(r.PrimarySearchResults);
    });
    
    NOT OK SharePoint SEARCH QUERY
     
    pnp.sp.search(<SearchQuery>{
        Querytext: "text1", // DOES NOT HAVE DETAILED WHERE CLAUSE, NO ROW LIMIT, NO SELECT STATEMENT
    }).then((r: SearchResults) => {
        console.log(r.ElapsedTime);
        console.log(r.RowCount);
        console.log(r.PrimarySearchResults);
    });
    
    OK SharePoint CAML QUERY
    
    pnp.sp.web.lists.getByTitle("list1").items
    .select("Title", "Description")  // HAS SELECT STATEMENT
    .top(5)  // HAS TOP STATEMENT
    .filter(`Hidden eq false and Title eq '[Field's_Display_Name]'`)  // HAS FILER CLAUSE
    .get()
    .then((items: any[]) => {
        console.log(items);
    });
    
    NOT OK SharePoint CAML QUERY
     
    pnp.sp.web.lists.getByTitle("list1").items  // WILL RETRIEVE ALL THE ITEMS IN A LIST!
    .get()
    .then((items: any[]) => {
        console.log(items);
    });

JavaScript bundle size and tools for identifying bundle size issues

  • All JavaScript files deployed to production should be minimized
  • The count of the bundle files does not matter that much since SharePoint uses HTTP2 and most of the modern browsers support it, actually is better to have few smaller files transferred async at the same time than one big bundle js file
  • Web pack Bundle Analyzer can be used to check the size of every bundle and the dependencies in it. See how to set it here
  • External heavy on size libraries should not be bundled with the webparts, but should be hosted as external library. See how can be done here
  • Common shared code/library used by different web parts should be bundled separately

SharePoint or Azure CDN to be used for external JavaScript

  • Use SharePoint CDN to load additional JavaScript files to ensure fast and cached load
            ○ Use Office 365 private CDN to secure assets if authorization on the origins are required.

SharePoint Image optimization

  • Use default images provided by search api for modern site pages since they are resized by default - PictureThumbnailURL.
  • Use image _layouts/15/getpreview.ashx service to render image where possible. More information here
  • Limit item counts in slider web part where hidden items have reference to images.
            ○ Use load on-demand when show more is clicked
  • Use Data Uri, base64 encoded, for web part common icons, and bundle it separately.
            ○ Use this strategy only for desktop, mobile device has limited CPU and battery
    

SharePoint Framework Performance tools, using the Chrome Developer tools

  • Chrome developer tools performance tab -> main (section) should be used to spot performance bottlenecks in the JavaScript main thread caused by web parts we create
  • Chrome developer tools performance tab -> network (section) -> should be used to spot latency and bundle size issues
  • How to use it here Web Performance Tooling - Google I/O 2016
  • Additionally, Chrome developer tools Audit tab can be used to spot general, high level performance and accessibility issues
  • Chrome developer tools network tab -> bandwidth(online) dropdown should be used to simulate slower mobile network.
    

Compute, Loops, Data Structures and Algorithm Time Complexity (JavaScript/Typescript)

  • Nested loops are bad for performance. Try to resolve it with sort then loop instead of loop in a loop, works in most of the cases
  • Working with JavaScript array indexes is faster than using loop or .find() functions
  • Loop after another loop in better than nested loop
  • Use promises or async, await for time consuming function, the promises can be used not only for ajax calls, but also for time consuming functions so they can be executed async.
    

More information can be found at
https://www.geeksforgeeks.org/analysis-of-algorithms-set-4-analysis-of-loops/
http://bigocheatsheet.com/
https://www.geeksforgeeks.org/data-structures/
https://www.geeksforgeeks.org/time-complexities-of-all-sorting-algorithms/

Advanced hacks

  • Add time consuming function at the end of the JavaScript main thread setTimeout(func, 0)
  • User GPU compute instead of CPU with CSS tricks
  • Load multiple promises async if they are not dependent of each other (so http requests are fired at the same time and will complete faster) rather than waiting on to complete the other for no reason
  • Web worker can be used for a long running background process
  • Virtual DOM is handled by framewroks as React js or Angular

Microsoft recommendations

Very good guidance on the Performance guidance for SharePoint Online portals page.

Conclusion

Performance is Feature #1. Before with SharePoint on-premise we had to optimize backed code or scale farm properly to get better performance. Now with SharePoint Online we are after perceived performance programming and more tricks on the front end, using the browser and javascript features since we are not in control in fine tune the web services.

Thanks to Xiyuan Zeng from Spanish point

Posted on

Tags: Office365, SPFx, SharePoint Framework, React, Performance, Optimization, SharePoint page faster load times

Comments