Optimizing scripts

In the process of output generation, the execution of scripts may take up more time than necessary. To optimize a template, it helps to disable scripts that don't have an effect on the output; see Managing scripts.

This topic presents a number of other ways to speed up script execution by optimizing the scripts.

Use an ID as selector

Scripts (except Control Scripts) start with a query. The selector in the second column in the Scripts pane is what a script looks for in the template. If you've used the drag-and-drop method (without pressing the Alt or Ctrl key) to insert a data field in a template, the selector is a small text: the name of the data field surrounded by @ signs, @firstname@ for example.

Looking for text in a text is a less optimized operation and may impact output speeds in longer documents. To speed up the output process, point the script to the element that contains the placeholder, by using its ID as selector. This narrows the scope of the search and results in a very fast query, as elements with an ID are indexed by Connect Designer's layout engine.

To learn how to put a placeholder or placeholders inside an element that has an ID, see Boxes. To use that ID as the script's selector: double-click the script in the Scripts pane and change the Find method to Selector and Text, or to Selector if the placeholder is the only content of the container. Enter the ID of the wrapper element in the Selector field, preceded by #, for example: #firstname.

When using the drag-and-drop method to insert data fields in a template:

  • Press the Alt key while dragging, to wrap the placeholder in a span, give the span an ID and have that ID used as the script's selector.
  • Press the Ctrl key while dragging, to wrap the placeholder in an absolute positioned box (a div) at the cursor position. A unique ID is assigned to the box and used as the script's selector.

Avoid DOM manipulations

The Scripting API of the Designer is a very powerful tool to manipulate and personalize your document. But keep in mind that DOM manipulation commands like append(), prepend(), before() and after() are resource intensive.

Try avoiding DOM modifications, especially within loops. Storing the content in a variable and appending the information after the loop is more efficient: this way, the template will be touched only once.

Example

The following example loads a snippet into a variable and uses the find() and text() commands of the Designer scripting API.

var labelElm = loadhtml('snippets/label.html');
for(var i = 0; i < record.tables.products.length; i++) {
	var label = labelElm.clone();
	label.find('@ProductLabel@').text(record.tables.products[i].ProductDescription);
	results.after(label);
}

What's wrong with this code is that it inserts the personalized information within the loop. The after() command runs as many times as there are records in the detail table 'products'.

The script below is much more efficient: it adds the personalized content to a string called labelStr and only calls after() after the for loop.

var labelElm = loadhtml('snippets/label.html');
var labelStr = "";
for( var i = 0; i < record.tables.products.length); i++) {
	var label = labelElm.clone();
	label.find('@ProductLabel@').text(record.tables.products[i].ProductDescription);
	labelStr += label;
}
results.after(labelStr);

Use replace()

When personalizing HTML fragments retrieved from a snippet or from the template itself, JavaScript's replace() method shows the best performance.

Replace() can only be used on Strings, while the commands loadhtml() and query() return or a QueryResult, which is a set of strings, like the results object.

A QueryResult allows you to perform DOM manipulations like adding and removing elements, adding and removing CSS classes etc. When the required manipulations are limited to find/replace actions, you could change the QueryResult into a string. This allows you to replace text using the replace() method.

For this, you could use toString():

var labelSnippet = loadhtml('snippets/label.html').toString();

Or you could copy the HTML of the QueryResults to a variable:

var block = results.html();

Example

var labelSnippet = loadhtml('snippets/label.html').toString();
var labelStr = "";
for( var i = 0; i < record.tables.detail.length; i++) {
	var label = labelSnippet;
	label = label.replace('#', i);
	label = label.replace('@product@', record.tables.detail[i].fields['product']);
	label = label.replace('@notes@', record.tables.detail[i].fields['notes']);
	label = label.replace('@netweight@', record.tables.detail[i].fields['netweight']);
	labelStr += label;
}
results.after(labelStr);
The replace() method as used in the above example replaces only the first occurrence of the search string. To replace every occurrence of a search string in a given string, use a regular expression. In the following line of code, the regular expression /@product@/g makes replace() search for all occurrences of the string @product@ in the label string:
label = label.replace(/@product@/g, record.tables.detail[i].fields['product']);

In this example, @product@ is a pattern (to be used in a search) and g is a modifier (to find all matches rather than stopping after the first match). For more information about possible regular expressions, see https://www.w3schools.com/js/js_regexp.asp.

The script in this how-to: Translate and replace script uses the replace() method with a regular expression.

Replace several placeholders in one script

Suppose there are 20 different placeholders in a postcard (for the address, account and customer details, a promo code, the due date, discounts, a link to a personalized landing page etc.). Typically this would require 20 queries. Even after optimizing these scripts by using an ID as selector for those scripts, there are still 20 scripts, 20 queries to run.

If there was only one query, one single script to do all the work, the output could be generated much faster. Reducing the number of scripts improves the performance of the template. How to do this?

First, wrap the content that contains all of the placeholders in one (inline) Box and give that Box or Span an ID (on the Attributes pane). Next, create a script that uses that ID as selector. Then replace all placeholders in the script and put the content back in the template.

This is similar to working with snippets, but in this case the element is extracted from the actual template.

Example

The following script replaces all of the placeholders on a postcard. It takes advantage of the JavaScript replace() command. Assuming that the ID of the block that requires personalization is promoblock, the script has to have its selector set to #promoblock.

var block = results.html();
var data = record.fields;
block = block.replace('@name@',data.first + ' ' + data.last);
block = block.replace('@address@',data.address);
block = block.replace('@zip@',data.zip);
block = block.replace('@city@',data.city);
block = block.replace('@country@',data.country);
block = block.replace('@saldo@',data.saldo);
block = block.replace('@promo@',data.promo);
block = block.replace('@customercode@', data.customercode);
…
results.html(block);

The first line retrieves the HTML of the promo block and stores it in a variable called block. To make the code more readible, the fields from the record are stored in a variable named data. After replacing the placeholders by values, the script replaces the HTML of the promoblock with the personalized string.

Other resources

There are also many resources online to help learn about JavaScript performance and coding mistakes. See for example:

Note that most resources on the web are about JavaScript in the browser, but the greatest majority of the tips do, indeed, apply to scripts in general, wherever they are used.