---
schema_version: "1"
id: 6deb189692f81ddd25275da5c5b61ae653bfafb0c1bd0e6fe40e14eac4450d78
title: Tableau JavaScript API Concepts--Asynchronous Calls
collection: tableau
version: current
locale: en-us
portal_url: https://docs.salesforce.com/tableau/current/en-us/api/js_api/JavaScriptAPI/js_api_concepts_asynchronous_calls.md
canonical_url: https://help.tableau.com/current/api/js_api/en-us/JavaScriptAPI/js_api_concepts_asynchronous_calls.htm
source_site: help.tableau.com
content_type: documentation
content_hash: 256c07e9c6c01bd5746febd21d3e745cc0ad387410c1beaaa0556112c10787d2
description: Important changes for the Tableau JavaScript API
---
[Skip to main content](#main-content)

# Behavior of Asynchronous Calls

**Important changes for the Tableau JavaScript API**

As of February 2024, the Tableau JavaScript API is deprecated. Use the Embedding API v3 instead for embedding interactive views into web pages and applications. For guidance on embedding Tableau views, see the [Tableau Embedding API v3 Help](https://help.tableau.com/current/api/embedding_api/en-us/index.html).

By default, calls are asynchronous since many of them may require a roundtrip to the server. Methods use the following naming convention:

- Asynchronous calls are indicated by an `Async` suffix on the method name, for example, `Worksheet.applyFilterAsync()`.
- Asynchronous calls return a `Promise` object, allowing chaining.

The Tableau JavaScript API uses the [CommonJS Promises/A standard](http://wiki.commonjs.org/wiki/Promises/A). The premise behind Tableau's implementation is that asynchronous methods return an object that has a `then` method in the following form:

```
.then(fulfilledHandler, errorHandler)
```

The `fulfilledHandler` is called when the promise is fulfilled (on success). The `errorHandler` is called when a promise fails. All arguments are optional and non-function values are ignored.

## Chaining Promises

The promised result of an asynchronous method is passed as the parameter to the next `then()` method. For example:

```
var activeSheet;

viz.getWorkbook().activateSheetAsync("Sheet 1")
  .then(selectLemon).then(filterToLemonAndMint);

function selectLemon(sheet) {
  activeSheet = sheet;
  return sheet.selectMarksAsync("Product", "Lemon", "replace");
}

function filterToLemonAndMint() {
  return activeSheet.applyFilterAsync("Product", ["Lemon", "Mint"], "replace");
}
```

The result of `activateSheetAsync()` is a promise to eventually return the `Sheet` object that was activated, which is passed as the first parameter to the `selectLemon()` method. Notice that the `selectLemon()` method returns a `Promise` object (the return value of the `selectMarksAsync()` method), not the result after the marks have been selected. However, since it's a `Promise` object, the next `then()` method is not called until that promise is fulfilled.

If a link in the chain is added after the promise has been fulfilled, the callback will be immediately called with the value that was previously returned. As the programmer, this means you don't need to determine if the response has already been received from the server. The asynchronous methods will always be called, whether it's now or later.

```
var promise = viz.getWorkbook().activateSheetAsync("Sheet 1");
// Pretend that activatSheeteAsync() has already returned from the server.
promise.then(callback);
// callback will be called immediately using the Sheet object
// returned from activateSheetAsync()
```

## Return Values of Then() Methods

Whatever is returned in a `then()` method will get passed as the first parameter to the next `then()` method. It can be a scalar value (`Number`, `Boolean`, `String`, etc.), an object, or another `Promise`. The infrastructure will automatically wrap non-`Promise` values into a `Promise` value so that they can be chained.

```
viz.getWorkbook().activateSheetAsync("Sheet 1")
.then(function (sheet) {
     return "First link";
})
.then(function (message) {
     if (message === "First link") { alert("Expected"); }
     // no return value here means nothing is passed to the next link
})
.then(function () {
});
```

## Breaking Out of a Chain

Technically, there's no way to break out of a chain since that would invalidate the guarantee that subsequent links in the chain will be called. If there is an exception thrown in part of the chain, the rest of the chain is run but the `errorHandler` is called instead of the `fulfilledHandler`.

If a link in the chain depends on the results of earlier links, then you should write an `if` statement to check your condition. Here's an example:

```
viz.getWorkbook().activateSheetAsync("Sheet 1")
.then(function (sheet) {
  // I'm returning a Promise
  return sheet.selectMarksAsync("Product", "NoProduct", "replace");
})
.then(function () {
  return viz.getWorkbook().getActiveSheet().getSelectedMarksAsync();
})
.then(function (marks) {
  // The getSelectedMarksAsync call succeeded, but no marks were selected
  // because there are not any marks corresponding to "NoProduct".
  if (marks.length === 0) {
    throw new Error("No marks selected");
  }
  var firstMarkValue = marks[0].getPairs().get("Product").value;
  return sheet.applyFilterAsync("Product", firstMarkValue, "replace");
})
.then(function (filterName) {
  // applyFilterAsync succeeded
}, function(err) {
  if (err.message === "No marks selected") {
    alert("This was caused by the first link above");
  }
})
.otherwise(function (err) {
  alert("We handled the error above, so it's not propagated to this handler.");
});
```

If a callback is not provided (or is null or undefined), then the results are passed to the next link in the chain:

```
viz.getWorkbook().activateSheetAsync("Sheet 1")
.then()
.then(function (sheet) {
  // this is called
});
```

In this way, you can specify a single `otherwise` function to handle all errors in the chain. The `always` function works the same way, but it is called regardless of success or failure. The `then/otherwise/always` functions work similarly to a `try/catch/finally` block.

```
viz.getWorkbook().activateSheetAsync("Sheet 1")
.then(function () {
     return sheet.selectMarksAsync(...);
})
.then(function (marks) {
     // Do something with the marks.
})
.otherwise(function (err) {
     // I'm handling all errors in one place.
     console.log(err.message);
})
.always(function () {
    // Do some cleanup or logging
});
```