Newer Version Available

This content describes an older version of this product. View Latest

Asynchronous Code in Components

Hackers can manipulate the timing of asynchronous code to produce malicious results. To preserve current execution context, wrap asynchronous function calls or batch actions into a single request.

When you use an asynchronous function such as setTimeout() and setInterval() to reference a component, you exit the framework’s lifecycle. If you navigate elsewhere in the user interface while asynchronous code is executing, the framework unrenders and destroys the component that made the asynchronous request. You can still have a reference to that component, but it’s no longer valid. Hackers exploit this vulnerability in harmful ways, for example, crash an app.

To reenter the framework safely, wrap the code in the $A.getCallback() function. Then, to ensure that the component is still valid, use the component.isValid() function before executing anything in the callback. Alternatively, batch multiple actions into one request by using enqueueAction().

This vulnerability doesn’t apply to components created against the Summer ’17 release (API v40.0) or later.

Note

These examples depict the security violation and how to fix it.

Aura Example

The setInterval() function gives you access to the document object model (DOM). However, accessing the DOM with setInterval() occurs in a context outside of the Lightning framework. There are no guarantees about the parent component’s state—it’s possible the function doesn’t have a parent component at all. If the state changes, the callback function can act on data that it doesn’t own, or it can wait for data that never shows up. In these scenarios, the app throws an error message that halts the entire Salesforce page, and the component stops responding.
1vars.Timer = setInterval(function(){ helper.action(component); },1);

Revised Code Using getCallback() Example

To reenter the framework safely, wrap the code in the $A.getCallback() function. Then, to ensure that the component is still valid, use the component.isValid() function before executing anything in the callback.

Use $A.getCallback() to wrap any code that accesses a component outside the normal re rendering lifecycle, such as in a setTimeout() or setInterval() call. $A.getCallback() preserves the current execution context and grants the correct access level to the asynchronous code. Otherwise, the framework loses context and only allows access to global resources.

1window.setTimeout(
2   $A.getCallback(function() {
3      if(cmp.isValid()){ 
4         cmp.set("v.visible", true); 
5      }
6   }), 5000
7);

Revised Code Using enqueueAction() Example

Alternatively, use enqueueAction(), which adds the server-side controller action to the queue of actions to be executed. Rather than sending a separate request for each individual action, the framework processes the event chain and batches the actions in the queue into one request. The actions are asynchronous and have callbacks.

1var action = component.get(“c.usually_a_server_side_controller”);
2action.setCallback(this, function()(response) {...});
3$A.enqueueAction(action2);

To learn more, check out our Secure Client-Side Development module on Trailhead.