Testing

Async Functions: Browser Support, Features, Limitations

Async functions support Chrome 55+, Edge 15+, Firefox 52+, Safari 11+, Opera 42+, and Samsung Internet 6.2+. See full async functions browser support.

Author

Prince Dewani

May 1, 2026

Async functions are a JavaScript language feature defined in the ECMA-262 specification that lets you write Promise-based code using the async and await keywords. They support Chrome 55+, Edge 15+, Firefox 52+, Safari 11+ on macOS and iOS, Opera 42+, Samsung Internet 6.2+, and Opera Mobile 80+, while Internet Explorer never added support.

This guide covers what async functions are, the browsers that support them, the key features, the difference from Promises, fallback options for older browsers, and known issues.

What are async functions?

Async functions are JavaScript functions declared with the async keyword. They always return a Promise, automatically wrap return values in Promise.resolve, and let you pause execution at await expressions. The TC39 committee added them so that Promise-based code reads top to bottom instead of as a chain of .then() callbacks.

Which browsers support async functions?

Async functions ship by default in every modern browser engine. Internet Explorer never added the syntax, and a few mobile browsers needed several major versions to catch up to their desktop counterparts.

Loading browser compatibility data...

Async functions compatibility in Chrome

Chrome supports async functions from Chrome 55 on Windows, macOS, Linux, ChromeOS, and Android. Chrome 4 to 54 did not support the syntax at all and threw a SyntaxError at parse time when the engine encountered the async keyword in front of a function declaration.

Async functions compatibility in Edge

Microsoft Edge supports async functions by default from Edge 15 on Windows. Edge 14 had async functions disabled by default behind the about:flags Experimental JavaScript features toggle, and Edge 12 to 13 did not support the syntax at all. Chromium-based Edge inherits Chrome 79+ behavior on Windows, macOS, Linux, and Android.

Async functions compatibility in Firefox

Firefox supports async functions from Firefox 52 on Windows, macOS, Linux, and Android. Firefox 2 to 51 did not support the syntax at all, and there was no flag in earlier builds. Firefox for Android picked up async functions in the same release cycle as desktop Firefox 52.

Async functions compatibility in Safari

Safari supports async functions from Safari 11 on macOS High Sierra and from Safari 11 on iOS 11. Safari 3.1 to 10.1 on macOS and Safari 3.2 to 10.3 on iOS did not support async or await. Early Safari 11 builds had a known bug parsing the negation operator in front of an awaited expression, which WebKit fixed in later 11.x point releases.

Async functions compatibility in Opera

Opera supports async functions from Opera 42 on Windows, macOS, and Linux through the Chromium 55 base. Opera Mobile picked up async functions in Opera Mobile 80 on Android. Opera 9 to 41 on desktop and Opera Mobile 10 to 12.1 on Android did not support the syntax.

Async functions compatibility in Samsung Internet

Samsung Internet supports async functions from Samsung Internet 6.2 on Galaxy phones and tablets running Android. Samsung Internet 4.0 to 5.4 did not support the syntax. Newer Samsung Internet builds align with the underlying Chromium release, so async function support extends to every modern Galaxy device.

Async functions compatibility in Android Browser

The legacy stock Android Browser, frozen at version 4.4 before Chrome for Android took over, did not support async functions. Modern Android Browser builds (147) ship async functions by default. On any current Android phone, use Chrome for Android, Samsung Internet, or another Chromium-based browser to run async function code.

Async functions compatibility in Internet Explorer

Internet Explorer never added async function support. IE 5.5 through IE 11 cannot parse the async keyword and throw a SyntaxError before the page runs any code. Microsoft has retired Internet Explorer, so use Edge, Chrome, or Firefox, or transpile your code with Babel and the regenerator runtime if you must run on IE.

Note

Note: Async function support varies across older Safari, mobile browsers, and Internet Explorer. Test it on real browsers and OS with TestMu AI. Try TestMu AI free!

What are the key features of async functions?

Async functions add a small set of language features on top of Promises. Each one trades a chain of .then() and .catch() calls for cleaner top-to-bottom code.

  • Implicit Promise return: An async function always returns a Promise. A plain return value is wrapped in Promise.resolve, and a thrown error becomes a Promise.reject, so callers can always chain .then or await the result.
  • The await keyword: Inside an async function, await pauses execution until the awaited Promise settles. The function then resumes with the resolved value or rethrows the rejection as a normal exception.
  • Try/catch error handling: Awaited Promise rejections surface as exceptions, so a single try/catch block can wrap multiple awaits. This replaces the .catch() chain that pure-Promise code needs.
  • Multiple syntax forms: async works on function declarations, function expressions, arrow functions, object methods, and class methods. Constructors, getters, and setters cannot be async.
  • Top-level await in modules: Inside an ES module, await can sit at the top level without an enclosing async function. This lets a module pause its own evaluation while a fetch or dynamic import resolves.
  • Concurrent awaits with Promise.all: await Promise.all([a(), b(), c()]) runs three async calls in parallel and resumes when every Promise settles. Promise.allSettled and Promise.race compose the same way.
  • Async iteration with for await...of: for await (const chunk of stream) iterates over an async iterable, which makes streaming reads from the Fetch API or readable streams a single loop instead of recursive Promise chains.

What is the difference between async functions and Promises?

An async function is a syntax wrapper around Promises, so the two work together rather than competing. The table below shows how the syntax, control flow, and error handling differ in practice.

DimensionAsync functionsPromises
Syntax styleTop-to-bottom code with awaitChained .then() and .catch() callbacks
Return typeAlways a Promise (wrapped automatically)Always a Promise (constructed explicitly)
Error handlingtry/catch around awaits.catch() handler at the end of the chain
Conditional flowStandard if/else and loops with awaitNested .then() callbacks or helper functions
Concurrencyawait Promise.all for parallel workPromise.all, Promise.race, Promise.allSettled directly
Browser supportChrome 55+, Edge 15+, Firefox 52+, Safari 11+Chrome 32+, Edge 12+, Firefox 29+, Safari 8+
Best fitSequential awaits, readable error paths, modern codeLibrary APIs, low-level control, IE-compatible code
...

How do you use async functions in older browsers?

Run modern source through Babel and ship the transpiled output to any browser that lacks async support. Babel rewrites async and await into a generator-based state machine, which Internet Explorer 11 and old Safari can execute with a tiny runtime polyfill.

  • Install Babel: Add @babel/core, @babel/cli, and @babel/preset-env to your project as dev dependencies through npm install.
  • Add the regenerator runtime: Run npm install regenerator-runtime and import it once at the top of your entry file with import "regenerator-runtime/runtime".
  • Configure the targets: In babel.config.json, set targets to the browsers you must support, for example { "ie": "11", "safari": "10" }. Babel turns on the right transforms for each target.
  • Compile your code: Run npx babel against your src folder and let it write the output to a dist folder. Babel converts every async function in src into a regenerator state machine in dist that runs on ES5.
  • Confirm in the target browser: Open the compiled bundle in Internet Explorer 11 or your oldest target, paste the snippet below into the DevTools console, and check that the user object prints without a SyntaxError.
async function getUser(id) {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
        throw new Error("User fetch failed: " + response.status);
    }
    const user = await response.json();
    return user;
}

(async () => {
    try {
        const user = await getUser(42);
        console.log("User loaded:", user.name);
    } catch (error) {
        console.error("Could not load user:", error);
    }
})();

If the console reports "regeneratorRuntime is not defined", the polyfill import is missing. Add import "regenerator-runtime/runtime" before any module that uses async functions and rebuild.

...

What are the known issues with async functions?

Async functions are stable, but a handful of edge cases trip up developers and add cross-browser bugs. Most of them come from the gap between language semantics and how each engine schedules micro-tasks.

  • Internet Explorer cannot parse the syntax: IE 5.5 through 11 throw a SyntaxError before the page runs. Any bundle that ships raw async syntax breaks IE outright, so transpile to ES5 with Babel before deployment.
  • Sequential awaits look concurrent but are not: const [a, b] = [await fetchA(), await fetchB()] runs the calls one after the other. Use await Promise.all([fetchA(), fetchB()]) when the two requests are independent.
  • Unhandled rejections in sequential awaits: If an earlier await resolves and a later one rejects, the rejection can fire before the catch handler runs and surface as an unhandled rejection in the console.
  • Promise reference inequality: An async function that returns a Promise wraps it in a fresh Promise, so the returned reference is not equal to the original. Code that compares Promise identity with === breaks silently.
  • Top-level await blocks module loading: A module that awaits at the top level pauses every importer. Long-running top-level awaits delay app startup and can stall hydration on server-rendered pages.
  • await is not allowed in classic scripts: Top-level await works only inside ES modules. Inline scripts without type="module" throw a SyntaxError if you use await outside an async function.
  • Safari 11 negation parsing bug: Early Safari 11 misparsed if (!await foo()) as if it were !(await foo()). Patches in later Safari 11 point releases fixed the parser, but legacy iOS 11 devices still carry the bug.
  • Promise executor cannot be async: new Promise(async (resolve) => { ... }) is an anti-pattern. ESLint flags it because rejections inside the async executor become unhandled rejections instead of rejecting the new Promise.

In my experience, the trickiest production failure is shipping async function code through a CDN to a fleet that still includes Internet Explorer or old WebView builds. Always compile to ES5 with Babel, import regenerator-runtime once, and feature-detect (async () => {})().constructor.name === "AsyncFunction" before running modern paths.

Citations

All async function version numbers and platform notes in this guide come from these primary sources:

Author

Prince Dewani is a Community Contributor at TestMu AI, where he manages content strategies around software testing, QA, and test automation. He is certified in Selenium, Cypress, Playwright, Appium, Automation Testing, and KaneAI. Prince has also presented academic research at the international conference PBCON-01. He further specializes in on-page SEO, bridging marketing with core testing technologies. On LinkedIn, he is followed by 4,300+ QA engineers, developers, DevOps experts, tech leaders, and AI-focused practitioners in the global testing community.

Open in ChatGPT Icon

Open in ChatGPT

Open in Claude Icon

Open in Claude

Open in Perplexity Icon

Open in Perplexity

Open in Grok Icon

Open in Grok

Open in Gemini AI Icon

Open in Gemini AI

Copied to Clipboard!
...

3000+ Browsers. One Platform.

See exactly how your site performs everywhere.

Try it free
...

Write Tests in Plain English with KaneAI

Create, debug, and evolve tests using natural language.

Try for free

Frequently asked questions

Did you find this page helpful?

More Related Hubs

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests