Friday, November 11, 2011

Javascript: Maximum call stack size exceeded in Chrome

jQuery templates is very powerful mechanism of building client side rendering logic. But large templates are very expensive in terms of browser resources and not all browsers can deal with it. It was unexpected, but the most modern browser with the best javascript engine V8 - Google Chrome (I used version 16) failed to render large template.

The task was pretty straightforward - build html table with around 400 rows and 35 columns through jQuery templates. The table is quite big and probably it’s not the best UX to show such table to the user, but it is what it is. IE8/9, Firefox 7+ rendered everything perfectly, but then I checked Google Chrome and it failed with throwing the following error: RangeError: Maximum call stack size exceeded.

After very deep debugging of jQuery templates and jQuery I figured out the problem. jQuery templates library builds array of strings and then prepares nodes to insert them to the DOM. On large templates the resulting array is really big - in my case around 100k+ items. jQuery templates uses jQuery.map method which calls the following method in the end:

// Flatten any nested arrays
return ret.concat.apply( [], ret );

IE8/9 and Firefox process this amount of data absolutely fine, but Google Chrome - not. I prepared small script in jsfiddle and it looks Chrome cannot process even 70k items:


As a recommendation how to avoid this issue could be not having such number of items passed into the template or generate each item individually and insert it to the DOM - this will not create huge arrays and will work completely fine in all browsers.

Tuesday, November 1, 2011

How to remove SharePoint crawled properties

Recently I've been trying to remove crawled properties in one of my projects. The problem is that SharePoint 2010 doesn't have out of the box functionality to remove crawled properties. I tried to delete the whole category with all crawled properties but SharePoint didn't let me do that saying that it's not possible to delete not empty category. It's pretty obvious, but just in case I checked category deletion in Reflector:










So no luck here as well. It throws exception when finds crawled properties within this category after it tried to delete them.


I started to dig into this issue and found the following blog post that helped me to find a solution:

http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2008/02/26/how-to-delete-crawled-properties.aspx

Unfortunately the solution above doesn't work as expected, even when there are no managed properties mapped to this crawled property. The thing is that the stored procedure that deletes unmapped properties (proc_MSS_DeleteCrawledPropertiesUnmappedForCategory) performs the following check - CP.IsMappedToContent = 0:

  1. Delete dbo.MSSCrawledProperties   
  2.    Where CrawledPropertyId in  
  3.    ( Select CP.CrawledPropertyId   
  4.       From MSSCrawledProperties as CP  
  5.       INNER JOIN dbo.MSSCrawledPropCategory as C  
  6.          on CP.Propset = C.Propset  
  7.       WHERE C.CategoryName = @CategoryName   
  8.         AND CP.IsMappedToContent = 0  
  9.         AND NOT EXISTS   
  10.           ( Select * from MSSSchemaPropertyMappings   
  11.             Where CrawledPropertyId = CP.CrawledPropertyId )   
  12.    )  
But for some crawled properties this value is always set to 1 even without mapped managed properties. So we need to set this value to 0 somehow. Fortunately Powershell comes to the rescue. There is IsMappedToContents property of crawled property object. And it's possible to set it to 0. Here is full piece of code with minimum checks that allows to remove crawled property.
  1. $searchAppName = "Search Service Application"  
  2. $categoryName = "Business Data"  
  3.   
  4. function RemoveCrawledProperty($crawledPropertyName)  
  5. {  
  6.     $category = Get-SPEnterpriseSearchMetadataCategory -Identity $categoryName -SearchApplication $searchAppName  
  7.     $crawledProperty =  
  8.         Get-SPEnterpriseSearchMetadataCrawledProperty -Name $crawledPropertyName -SearchApplication $searchAppName -Category $category  
  9.     if ($crawledProperty)  
  10.     {  
  11.         $mappings = Get-SPEnterpriseSearchMetadataMapping -SearchApplication $searchAppName -CrawledProperty $crawledProperty  
  12.         if ($mappings)  
  13.         {  
  14.             $mappings | Remove-SPEnterpriseSearchMetadataMapping -Confirm:$false  
  15.         }  
  16.         else  
  17.         {  
  18.             Write-Host "No mappings found for '$crawledPropertyName'." -foregroundcolor yellow  
  19.         }  
  20.         $crawledProperty.IsMappedToContents = $false  
  21.         $crawledProperty.Update()  
  22.         $category.DeleteUnmappedProperties()  
  23.     }  
  24.     else  
  25.     {  
  26.         Write-Host "Crawled property '$crawledPropertyName' not found." -foregroundcolor yellow  
  27.     }  
  28. }  
Hope it will be helpful to someone.