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 or class 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. The selector can be a text, HTML/CSS tags, or a combination of text and HTML/CSS tags.

Looking for text in a template is a less optimized operation and may impact output speeds in longer documents. To speed up the output process, it is recommended to use an ID or class as selector instead. This narrows the scope of the search and results in a very fast query, as elements with an ID or class are indexed by Connect Designer's layout engine.

For information about how to give an element an ID or class, see ID and class.
See also: Quick-start a script for a specific ID or class.

Targeting text

Text in itself cannot have an ID or class, but the element that contains it can. The smallest possible container of text is a Span. To learn how to put text inside a Span, see Span. Give the Span an ID or class and use that as the script's selector.

To target text in a bigger container (a paragraph, for example), change the Find method of the script to Selector and Text, use the ID or class of the container element as Selector and type the text in the Text field.

When you use the drag-and-drop method (without pressing the ALT key) to insert variable data into a template, the script's selector is by default the class of the element - a Span or Div - in which the placeholder is wrapped. For more information see: Inserting variable data directly (drag-and-drop).

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.

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.