CINXE.COM
Using Web Workers - Web APIs | MDN
<!doctype html><html lang="en-US" prefix="og: https://ogp.me/ns#"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="https://developer.mozilla.org/favicon-48x48.bc390275e955dacb2e65.png"/><link rel="apple-touch-icon" href="https://developer.mozilla.org/apple-touch-icon.528534bba673c38049c2.png"/><meta name="theme-color" content="#ffffff"/><link rel="manifest" href="https://developer.mozilla.org/manifest.f42880861b394dd4dc9b.json"/><link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="MDN Web Docs"/><title>Using Web Workers - Web APIs | MDN</title><link rel="alternate" title="Verwendung von Web Workern" href="https://developer.mozilla.org/de/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="de"/><link rel="alternate" title="Usando Web Workers" href="https://developer.mozilla.org/es/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="es"/><link rel="alternate" title="Utilisation des web workers" href="https://developer.mozilla.org/fr/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="fr"/><link rel="alternate" title="ウェブワーカーの使用" href="https://developer.mozilla.org/ja/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="ja"/><link rel="alternate" title="Использование Web Workers" href="https://developer.mozilla.org/ru/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="ru"/><link rel="alternate" title="使用 Web Worker" href="https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="zh"/><link rel="alternate" title="使用 Web Worker" href="https://developer.mozilla.org/zh-TW/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="zh-Hant"/><link rel="alternate" title="Using Web Workers" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" hrefLang="en"/><link rel="preload" as="font" type="font/woff2" href="/static/media/Inter.var.c2fe3cb2b7c746f7966a.woff2" crossorigin=""/><link rel="alternate" type="application/rss+xml" title="MDN Blog RSS Feed" href="https://developer.mozilla.org/en-US/blog/rss.xml" hrefLang="en"/><meta name="description" content="Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can make network requests using the fetch() or XMLHttpRequest APIs. Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa)."/><meta property="og:url" content="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"/><meta property="og:title" content="Using Web Workers - Web APIs | MDN"/><meta property="og:type" content="website"/><meta property="og:locale" content="en_US"/><meta property="og:description" content="Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can make network requests using the fetch() or XMLHttpRequest APIs. Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa)."/><meta property="og:image" content="https://developer.mozilla.org/mdn-social-share.d893525a4fb5fb1f67a2.png"/><meta property="og:image:type" content="image/png"/><meta property="og:image:height" content="1080"/><meta property="og:image:width" content="1920"/><meta property="og:image:alt" content="The MDN Web Docs logo, featuring a blue accent color, displayed on a solid black background."/><meta property="og:site_name" content="MDN Web Docs"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:creator" content="MozDevNet"/><link rel="canonical" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"/><style media="print">.article-actions-container,.document-toc-container,.language-menu,.main-menu-toggle,.on-github,.page-footer,.place,.sidebar,.top-banner,.top-navigation-main,ul.prev-next{display:none!important}.main-page-content,.main-page-content pre{padding:2px}.main-page-content pre{border-left-width:2px}</style><script src="/static/js/gtag.js" defer=""></script><script defer="" src="/static/js/main.1b60bff1.js"></script><link href="/static/css/main.959b5ea9.css" rel="stylesheet"/></head><body><script>if(document.body.addEventListener("load",(t=>{t.target.classList.contains("interactive")&&t.target.setAttribute("data-readystate","complete")}),{capture:!0}),window&&document.documentElement){const t={light:"#ffffff",dark:"#1b1b1b"};try{const e=window.localStorage.getItem("theme");e&&(document.documentElement.className=e,document.documentElement.style.backgroundColor=t[e]);const o=window.localStorage.getItem("nop");o&&(document.documentElement.dataset.nop=o)}catch(t){console.warn("Unable to read theme from localStorage",t)}}</script><div id="root"><ul id="nav-access" class="a11y-nav"><li><a id="skip-main" href="#content">Skip to main content</a></li><li><a id="skip-search" href="#top-nav-search-input">Skip to search</a></li><li><a id="skip-select-language" href="#languages-switcher-button">Skip to select language</a></li></ul><div class="page-wrapper category-api document-page"><div class="top-banner loading"><section class="place top container"></section></div><div class="sticky-header-container"><header class="top-navigation "><div class="container "><div class="top-navigation-wrap"><a href="/en-US/" class="logo" aria-label="MDN homepage"><svg id="mdn-docs-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 694.9 104.4" style="enable-background:new 0 0 694.9 104.4" xml:space="preserve" role="img"><title>MDN Web Docs</title><path d="M40.3 0 11.7 92.1H0L28.5 0h11.8zm10.4 0v92.1H40.3V0h10.4zM91 0 62.5 92.1H50.8L79.3 0H91zm10.4 0v92.1H91V0h10.4z" class="logo-m"></path><path d="M627.9 95.6h67v8.8h-67v-8.8z" class="logo-_"></path><path d="M367 42h-4l-10.7 30.8h-5.5l-10.8-26h-.4l-10.5 26h-5.2L308.7 42h-3.8v-5.6H323V42h-6.5l6.8 20.4h.4l10.3-26h4.7l11.2 26h.5l5.7-20.3h-6.2v-5.6H367V42zm34.9 20c-.4 3.2-2 5.9-4.7 8.2-2.8 2.3-6.5 3.4-11.3 3.4-5.4 0-9.7-1.6-13.1-4.7-3.3-3.2-5-7.7-5-13.7 0-5.7 1.6-10.3 4.7-14s7.4-5.5 12.9-5.5c5.1 0 9.1 1.6 11.9 4.7s4.3 6.9 4.3 11.3c0 1.5-.2 3-.5 4.7h-25.6c.3 7.7 4 11.6 10.9 11.6 2.9 0 5.1-.7 6.5-2 1.5-1.4 2.5-3 3-4.9l6 .9zM394 51.3c.2-2.4-.4-4.7-1.8-6.9s-3.8-3.3-7-3.3c-3.1 0-5.3 1-6.9 3-1.5 2-2.5 4.4-2.8 7.2H394zm51 2.4c0 5-1.3 9.5-4 13.7s-6.9 6.2-12.7 6.2c-6 0-10.3-2.2-12.7-6.7-.1.4-.2 1.4-.4 2.9s-.3 2.5-.4 2.9h-7.3c.3-1.7.6-3.5.8-5.3.3-1.8.4-3.7.4-5.5V22.3h-6v-5.6H416v27c1.1-2.2 2.7-4.1 4.7-5.7 2-1.6 4.8-2.4 8.4-2.4 4.6 0 8.4 1.6 11.4 4.7 3 3.2 4.5 7.6 4.5 13.4zm-7.7.6c0-4.2-1-7.4-3-9.5-2-2.2-4.4-3.3-7.4-3.3-3.4 0-6 1.2-8 3.7-1.9 2.4-2.9 5-3 7.7V57c0 3 1 5.6 3 7.7s4.5 3.1 7.6 3.1c3.6 0 6.3-1.3 8.1-3.9 1.8-2.7 2.7-5.9 2.7-9.6zm69.2 18.5h-13.2v-7.2c-1.2 2.2-2.8 4.1-4.9 5.6-2.1 1.6-4.8 2.4-8.3 2.4-4.8 0-8.7-1.6-11.6-4.9-2.9-3.2-4.3-7.7-4.3-13.3 0-5 1.3-9.6 4-13.7 2.6-4.1 6.9-6.2 12.8-6.2 5.7 0 9.8 2.2 12.3 6.5V22.3h-8.6v-5.6h15.8v50.6h6v5.5zM493.2 56v-4.4c-.1-3-1.2-5.5-3.2-7.3s-4.4-2.8-7.2-2.8c-3.6 0-6.3 1.3-8.2 3.9-1.9 2.6-2.8 5.8-2.8 9.6 0 4.1 1 7.3 3 9.5s4.5 3.3 7.4 3.3c3.2 0 5.8-1.3 7.8-3.8 2.1-2.6 3.1-5.3 3.2-8zm53.1-1.4c0 5.6-1.8 10.2-5.3 13.7s-8.2 5.3-13.9 5.3-10.1-1.7-13.4-5.1c-3.3-3.4-5-7.9-5-13.5 0-5.3 1.6-9.9 4.7-13.7 3.2-3.8 7.9-5.7 14.2-5.7s11 1.9 14.1 5.7c3 3.7 4.6 8.1 4.6 13.3zm-7.7-.2c0-4-1-7.2-3-9.5s-4.8-3.5-8.2-3.5c-3.6 0-6.4 1.2-8.3 3.7s-2.9 5.6-2.9 9.5c0 3.7.9 6.8 2.8 9.4 1.9 2.6 4.6 3.9 8.3 3.9 3.6 0 6.4-1.3 8.4-3.8 1.9-2.6 2.9-5.8 2.9-9.7zm45 5.8c-.4 3.2-1.9 6.3-4.4 9.1-2.5 2.9-6.4 4.3-11.8 4.3-5.2 0-9.4-1.6-12.6-4.8-3.2-3.2-4.8-7.7-4.8-13.7 0-5.5 1.6-10.1 4.7-13.9 3.2-3.8 7.6-5.7 13.2-5.7 2.3 0 4.6.3 6.7.8 2.2.5 4.2 1.5 6.2 2.9l1.5 9.5-5.9.7-1.3-6.1c-2.1-1.2-4.5-1.8-7.2-1.8-3.5 0-6.1 1.2-7.7 3.7-1.7 2.5-2.5 5.7-2.5 9.6 0 4.1.9 7.3 2.7 9.5 1.8 2.3 4.4 3.4 7.8 3.4 5.2 0 8.2-2.9 9.2-8.8l6.2 1.3zm34.7 1.9c0 3.6-1.5 6.5-4.6 8.5s-7 3-11.7 3c-5.7 0-10.6-1.2-14.6-3.6l1.2-8.8 5.7.6-.2 4.7c1.1.5 2.3.9 3.6 1.1s2.6.3 3.9.3c2.4 0 4.5-.4 6.5-1.3 1.9-.9 2.9-2.2 2.9-4.1 0-1.8-.8-3.1-2.3-3.8s-3.5-1.3-5.8-1.7-4.6-.9-6.9-1.4c-2.3-.6-4.2-1.6-5.7-2.9-1.6-1.4-2.3-3.5-2.3-6.3 0-4.1 1.5-6.9 4.6-8.5s6.4-2.4 9.9-2.4c2.6 0 5 .3 7.2.9 2.2.6 4.3 1.4 6.1 2.4l.8 8.8-5.8.7-.8-5.7c-2.3-1-4.7-1.6-7.2-1.6-2.1 0-3.7.4-5.1 1.1-1.3.8-2 2-2 3.8 0 1.7.8 2.9 2.3 3.6 1.5.7 3.4 1.2 5.7 1.6 2.2.4 4.5.8 6.7 1.4 2.2.6 4.1 1.6 5.7 3 1.4 1.6 2.2 3.7 2.2 6.6zM197.6 73.2h-17.1v-5.5h3.8V51.9c0-3.7-.7-6.3-2.1-7.9-1.4-1.6-3.3-2.3-5.7-2.3-3.2 0-5.6 1.1-7.2 3.4s-2.4 4.6-2.5 6.9v15.6h6v5.5h-17.1v-5.5h3.8V51.9c0-3.8-.7-6.4-2.1-7.9-1.4-1.5-3.3-2.3-5.6-2.3-3.2 0-5.5 1.1-7.2 3.3-1.6 2.2-2.4 4.5-2.5 6.9v15.8h6.9v5.5h-20.2v-5.5h6V42.4h-6.1v-5.6h13.4v6.4c1.2-2.1 2.7-3.8 4.7-5.2 2-1.3 4.4-2 7.3-2s5.3.7 7.5 2.1c2.2 1.4 3.7 3.5 4.5 6.4 1.1-2.5 2.7-4.5 4.9-6.1s4.8-2.4 7.9-2.4c3.5 0 6.5 1.1 8.9 3.3s3.7 5.6 3.7 10.2v18.2h6.1v5.5zm42.5 0h-13.2V66c-1.2 2.2-2.8 4.1-4.9 5.6-2.1 1.6-4.8 2.4-8.3 2.4-4.8 0-8.7-1.6-11.6-4.9-2.9-3.2-4.3-7.7-4.3-13.3 0-5 1.3-9.6 4-13.7 2.6-4.1 6.9-6.2 12.8-6.2s9.8 2.2 12.3 6.5V22.7h-8.6v-5.6h15.8v50.6h6v5.5zm-13.3-16.8V52c-.1-3-1.2-5.5-3.2-7.3s-4.4-2.8-7.2-2.8c-3.6 0-6.3 1.3-8.2 3.9-1.9 2.6-2.8 5.8-2.8 9.6 0 4.1 1 7.3 3 9.5s4.5 3.3 7.4 3.3c3.2 0 5.8-1.3 7.8-3.8 2.1-2.6 3.1-5.3 3.2-8zm61.5 16.8H269v-5.5h6V51.9c0-3.7-.7-6.3-2.2-7.9-1.4-1.6-3.4-2.3-5.7-2.3-3.1 0-5.6 1-7.4 3s-2.8 4.4-2.9 7v15.9h6v5.5h-19.3v-5.5h6V42.4h-6.2v-5.6h13.6V43c2.6-4.6 6.8-6.9 12.7-6.9 3.6 0 6.7 1.1 9.2 3.3s3.7 5.6 3.7 10.2v18.2h6v5.4h-.2z" class="logo-text"></path></svg></a><button title="Open main menu" type="button" class="button action has-icon main-menu-toggle" aria-haspopup="menu" aria-label="Open main menu" aria-expanded="false"><span class="button-wrap"><span class="icon icon-menu "></span><span class="visually-hidden">Open main menu</span></span></button></div><div class="top-navigation-main"><nav class="main-nav" aria-label="Main menu"><ul class="main-menu nojs"><li class="top-level-entry-container active"><button type="button" id="references-button" class="top-level-entry menu-toggle" aria-controls="references-menu" aria-expanded="false">References</button><a href="/en-US/docs/Web" class="top-level-entry">References</a><ul id="references-menu" class="submenu references hidden inline-submenu-lg" aria-labelledby="references-button"><li class="apis-link-container mobile-only "><a href="/en-US/docs/Web" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / Web Technology</div><p class="submenu-item-description">Web technology reference for developers</p></div></a></li><li class="html-link-container "><a href="/en-US/docs/Web/HTML" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Structure of content on the web</p></div></a></li><li class="css-link-container "><a href="/en-US/docs/Web/CSS" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Code used to describe document style</p></div></a></li><li class="javascript-link-container "><a href="/en-US/docs/Web/JavaScript" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">General-purpose scripting language</p></div></a></li><li class="http-link-container "><a href="/en-US/docs/Web/HTTP" class="submenu-item "><div class="submenu-icon http"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTTP</div><p class="submenu-item-description">Protocol for transmitting web resources</p></div></a></li><li class="apis-link-container "><a href="/en-US/docs/Web/API" class="submenu-item "><div class="submenu-icon apis"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web APIs</div><p class="submenu-item-description">Interfaces for building web applications</p></div></a></li><li class="apis-link-container "><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web Extensions</div><p class="submenu-item-description">Developing extensions for web browsers</p></div></a></li><li class="apis-link-container desktop-only "><a href="/en-US/docs/Web" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web Technology</div><p class="submenu-item-description">Web technology reference for developers</p></div></a></li></ul></li><li class="top-level-entry-container "><button type="button" id="guides-button" class="top-level-entry menu-toggle" aria-controls="guides-menu" aria-expanded="false">Guides</button><a href="/en-US/docs/Learn" class="top-level-entry">Guides</a><ul id="guides-menu" class="submenu guides hidden inline-submenu-lg" aria-labelledby="guides-button"><li class="apis-link-container mobile-only "><a href="/en-US/docs/Learn" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="apis-link-container desktop-only "><a href="/en-US/docs/Learn" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="html-link-container "><a href="/en-US/docs/Learn/HTML" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Learn to structure web content with HTML</p></div></a></li><li class="css-link-container "><a href="/en-US/docs/Learn/CSS" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Learn to style content using CSS</p></div></a></li><li class="javascript-link-container "><a href="/en-US/docs/Learn/JavaScript" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">Learn to run scripts in the browser</p></div></a></li><li class=" "><a href="/en-US/docs/Web/Accessibility" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Accessibility</div><p class="submenu-item-description">Learn to make the web accessible to all</p></div></a></li></ul></li><li class="top-level-entry-container "><button type="button" id="mdn-plus-button" class="top-level-entry menu-toggle" aria-controls="mdn-plus-menu" aria-expanded="false">Plus</button><a href="/en-US/plus" class="top-level-entry">Plus</a><ul id="mdn-plus-menu" class="submenu mdn-plus hidden inline-submenu-lg" aria-labelledby="mdn-plus-button"><li class=" "><a href="/en-US/plus" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview</div><p class="submenu-item-description">A customized MDN experience</p></div></a></li><li class=" "><a href="/en-US/plus/ai-help" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">AI Help</div><p class="submenu-item-description">Get real-time assistance and support</p></div></a></li><li class=" "><a href="/en-US/plus/updates" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Updates</div><p class="submenu-item-description">All browser compatibility updates at a glance</p></div></a></li><li class=" "><a href="/en-US/plus/docs/features/overview" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Documentation</div><p class="submenu-item-description">Learn how to use MDN Plus</p></div></a></li><li class=" "><a href="/en-US/plus/docs/faq" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">FAQ</div><p class="submenu-item-description">Frequently asked questions about MDN Plus</p></div></a></li></ul></li><li class="top-level-entry-container "><a class="top-level-entry menu-link" href="/en-US/curriculum/">Curriculum <sup class="new">New</sup></a></li><li class="top-level-entry-container "><a class="top-level-entry menu-link" href="/en-US/blog/">Blog</a></li><li class="top-level-entry-container "><button type="button" id="tools-button" class="top-level-entry menu-toggle" aria-controls="tools-menu" aria-expanded="false">Tools</button><ul id="tools-menu" class="submenu tools hidden inline-submenu-lg" aria-labelledby="tools-button"><li class=" "><a href="/en-US/play" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Playground</div><p class="submenu-item-description">Write, test and share your code</p></div></a></li><li class=" "><a href="/en-US/observatory" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTTP Observatory</div><p class="submenu-item-description">Scan a website for free</p></div></a></li><li class=" "><a href="/en-US/plus/ai-help" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">AI Help</div><p class="submenu-item-description">Get real-time assistance and support</p></div></a></li></ul></li></ul></nav><div class="header-search"><form action="/en-US/search" class="search-form search-widget" id="top-nav-search-form" role="search"><label id="top-nav-search-label" for="top-nav-search-input" class="visually-hidden">Search MDN</label><input aria-activedescendant="" aria-autocomplete="list" aria-controls="top-nav-search-menu" aria-expanded="false" aria-labelledby="top-nav-search-label" autoComplete="off" id="top-nav-search-input" role="combobox" type="search" class="search-input-field" name="q" placeholder=" " required="" value=""/><button type="button" class="button action has-icon clear-search-button"><span class="button-wrap"><span class="icon icon-cancel "></span><span class="visually-hidden">Clear search input</span></span></button><button type="submit" class="button action has-icon search-button"><span class="button-wrap"><span class="icon icon-search "></span><span class="visually-hidden">Search</span></span></button><div id="top-nav-search-menu" role="listbox" aria-labelledby="top-nav-search-label"></div></form></div><div class="theme-switcher-menu"><button type="button" class="button action has-icon theme-switcher-menu small" aria-haspopup="menu"><span class="button-wrap"><span class="icon icon-theme-os-default "></span>Theme</span></button></div><ul class="auth-container"><li><a href="/users/fxa/login/authenticate/?next=%2Fen-US%2Fdocs%2FWeb%2FAPI%2FWeb_Workers_API%2FUsing_web_workers" class="login-link" rel="nofollow">Log in</a></li><li><a href="/users/fxa/login/authenticate/?next=%2Fen-US%2Fdocs%2FWeb%2FAPI%2FWeb_Workers_API%2FUsing_web_workers" target="_self" rel="nofollow" class="button primary mdn-plus-subscribe-link"><span class="button-wrap">Sign up for free</span></a></li></ul></div></div></header><div class="article-actions-container"><div class="container"><button type="button" class="button action has-icon sidebar-button" aria-label="Expand sidebar" aria-expanded="false" aria-controls="sidebar-quicklinks"><span class="button-wrap"><span class="icon icon-sidebar "></span></span></button><nav class="breadcrumbs-container" aria-label="Breadcrumb"><ol typeof="BreadcrumbList" vocab="https://schema.org/" aria-label="breadcrumbs"><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Web" class="breadcrumb" property="item" typeof="WebPage"><span property="name">References</span></a><meta property="position" content="1"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Web/API" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Web APIs</span></a><meta property="position" content="2"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Web/API/Web_Workers_API" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Web Workers API</span></a><meta property="position" content="3"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" class="breadcrumb-current-page" property="item" typeof="WebPage"><span property="name">Using Web Workers</span></a><meta property="position" content="4"/></li></ol></nav><div class="article-actions"><button type="button" class="button action has-icon article-actions-toggle" aria-label="Article actions"><span class="button-wrap"><span class="icon icon-ellipses "></span><span class="article-actions-dialog-heading">Article Actions</span></span></button><ul class="article-actions-entries"><li class="article-actions-entry"><div class="languages-switcher-menu open-on-focus-within"><button id="languages-switcher-button" type="button" class="button action small has-icon languages-switcher-menu" aria-haspopup="menu"><span class="button-wrap"><span class="icon icon-language "></span>English (US)</span></button><div class="hidden"><ul class="submenu language-menu " aria-labelledby="language-menu-button"><li class=" "><form class="submenu-item locale-redirect-setting"><div class="group"><label class="switch"><input type="checkbox" name="locale-redirect"/><span class="slider"></span><span class="label">Remember language</span></label><a href="https://github.com/orgs/mdn/discussions/739" rel="external noopener noreferrer" target="_blank" title="Enable this setting to automatically switch to this language when it's available. (Click to learn more.)"><span class="icon icon-question-mark "></span></a></div></form></li><li class=" "><a data-locale="de" href="/de/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>Deutsch</span><span title="Diese Übersetzung ist Teil eines Experiments."><span class="icon icon-experimental "></span></span></a></li><li class=" "><a data-locale="es" href="/es/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>Español</span></a></li><li class=" "><a data-locale="fr" href="/fr/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>Français</span></a></li><li class=" "><a data-locale="ja" href="/ja/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>日本語</span></a></li><li class=" "><a data-locale="ru" href="/ru/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>Русский</span></a></li><li class=" "><a data-locale="zh-CN" href="/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>中文 (简体)</span></a></li><li class=" "><a data-locale="zh-TW" href="/zh-TW/docs/Web/API/Web_Workers_API/Using_web_workers" class="button submenu-item"><span>正體中文 (繁體)</span></a></li></ul></div></div></li></ul></div></div></div></div><div class="main-wrapper"><div class="sidebar-container"><aside id="sidebar-quicklinks" class="sidebar" data-macro="DefaultAPISidebar"><button type="button" class="button action backdrop" aria-label="Collapse sidebar"><span class="button-wrap"></span></button><nav aria-label="Related Topics" class="sidebar-inner"><header class="sidebar-actions"><section class="sidebar-filter-container"><div class="sidebar-filter "><label id="sidebar-filter-label" class="sidebar-filter-label" for="sidebar-filter-input"><span class="icon icon-filter"></span><span class="visually-hidden">Filter sidebar</span></label><input id="sidebar-filter-input" autoComplete="off" class="sidebar-filter-input-field false" type="text" placeholder="Filter" value=""/><button type="button" class="button action has-icon clear-sidebar-filter-button"><span class="button-wrap"><span class="icon icon-cancel "></span><span class="visually-hidden">Clear filter input</span></span></button></div></section></header><div class="sidebar-inner-nav"><div class="in-nav-toc"><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In this article</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#web_workers_api">Web Workers API</a></li><li class="document-toc-item "><a class="document-toc-link" href="#dedicated_workers">Dedicated workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#shared_workers">Shared workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#about_thread_safety">About thread safety</a></li><li class="document-toc-item "><a class="document-toc-link" href="#content_security_policy">Content security policy</a></li><li class="document-toc-item "><a class="document-toc-link" href="#transferring_data_to_and_from_workers_further_details">Transferring data to and from workers: further details</a></li><li class="document-toc-item "><a class="document-toc-link" href="#embedded_workers">Embedded workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#further_examples">Further examples</a></li><li class="document-toc-item "><a class="document-toc-link" href="#other_types_of_workers">Other types of workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#debugging_worker_threads">Debugging worker threads</a></li><li class="document-toc-item "><a class="document-toc-link" href="#functions_and_interfaces_available_in_workers">Functions and interfaces available in workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#specifications">Specifications</a></li><li class="document-toc-item "><a class="document-toc-link" href="#see_also">See also</a></li></ul></section></div></div><div class="sidebar-body"><ol><li class="section"><a href="/en-US/docs/Web/API/Web_Workers_API">Web Workers API</a></li><li class="toggle"><details open=""><summary>Guides</summary><ol><li><em><a href="/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" aria-current="page">Using Web Workers</a></em></li><li><a href="/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers">Functions and classes available to Web Workers</a></li><li><a href="/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm">The structured clone algorithm</a></li><li><a href="/en-US/docs/Web/API/Web_Workers_API/Transferable_objects">Transferable objects</a></li></ol></details></li><li class="toggle"><details open=""><summary>Interfaces</summary><ol><li><a href="/en-US/docs/Web/API/DedicatedWorkerGlobalScope"><code>DedicatedWorkerGlobalScope</code></a></li><li><a href="/en-US/docs/Web/API/SharedWorker"><code>SharedWorker</code></a></li><li><a href="/en-US/docs/Web/API/SharedWorkerGlobalScope"><code>SharedWorkerGlobalScope</code></a></li><li><a href="/en-US/docs/Web/API/Worker"><code>Worker</code></a></li><li><a href="/en-US/docs/Web/API/WorkerGlobalScope"><code>WorkerGlobalScope</code></a></li><li><a href="/en-US/docs/Web/API/WorkerLocation"><code>WorkerLocation</code></a></li><li><a href="/en-US/docs/Web/API/WorkerNavigator"><code>WorkerNavigator</code></a></li></ol></details></li></ol></div></div><section class="place side"></section></nav></aside><div class="toc-container"><aside class="toc"><nav><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In this article</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#web_workers_api">Web Workers API</a></li><li class="document-toc-item "><a class="document-toc-link" href="#dedicated_workers">Dedicated workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#shared_workers">Shared workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#about_thread_safety">About thread safety</a></li><li class="document-toc-item "><a class="document-toc-link" href="#content_security_policy">Content security policy</a></li><li class="document-toc-item "><a class="document-toc-link" href="#transferring_data_to_and_from_workers_further_details">Transferring data to and from workers: further details</a></li><li class="document-toc-item "><a class="document-toc-link" href="#embedded_workers">Embedded workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#further_examples">Further examples</a></li><li class="document-toc-item "><a class="document-toc-link" href="#other_types_of_workers">Other types of workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#debugging_worker_threads">Debugging worker threads</a></li><li class="document-toc-item "><a class="document-toc-link" href="#functions_and_interfaces_available_in_workers">Functions and interfaces available in workers</a></li><li class="document-toc-item "><a class="document-toc-link" href="#specifications">Specifications</a></li><li class="document-toc-item "><a class="document-toc-link" href="#see_also">See also</a></li></ul></section></div></nav></aside><section class="place side"></section></div></div><main id="content" class="main-content "><article class="main-page-content" lang="en-US"><header><h1>Using Web Workers</h1></header><div class="section-content"><p>Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can make network requests using the <a href="/en-US/docs/Web/API/WorkerGlobalScope/fetch" title="fetch()"><code>fetch()</code></a> or <a href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> APIs. Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa).</p> <p>This article provides a detailed introduction to using web workers.</p></div><section aria-labelledby="web_workers_api"><h2 id="web_workers_api"><a href="#web_workers_api">Web Workers API</a></h2><div class="section-content"><p>A worker is an object created using a constructor (e.g. <a href="/en-US/docs/Web/API/Worker/Worker" title="Worker()"><code>Worker()</code></a>) that runs a named JavaScript file — this file contains the code that will run in the worker thread; workers run in another global context that is different from the current <a href="/en-US/docs/Web/API/Window"><code>window</code></a>. Thus, using the <a href="/en-US/docs/Web/API/Window"><code>window</code></a> shortcut to get the current global scope (instead of <a href="/en-US/docs/Web/API/Window/self" title="self"><code>self</code></a>) within a <a href="/en-US/docs/Web/API/Worker"><code>Worker</code></a> will return an error.</p> <p>The worker context is represented by a <a href="/en-US/docs/Web/API/DedicatedWorkerGlobalScope"><code>DedicatedWorkerGlobalScope</code></a> object in the case of dedicated workers (standard workers that are utilized by a single script; shared workers use <a href="/en-US/docs/Web/API/SharedWorkerGlobalScope"><code>SharedWorkerGlobalScope</code></a>). A dedicated worker is only accessible from the script that first spawned it, whereas shared workers can be accessed from multiple scripts.</p> <div class="notecard note"> <p><strong>Note:</strong> See <a href="/en-US/docs/Web/API/Web_Workers_API">The Web Workers API landing page</a> for reference documentation on workers and additional guides.</p> </div> <p>You can run whatever code you like inside the worker thread, with some exceptions. For example, you can't directly manipulate the DOM from inside a worker, or use some default methods and properties of the <a href="/en-US/docs/Web/API/Window"><code>window</code></a> object. But you can use a large number of items available under <code>window</code>, including <a href="/en-US/docs/Web/API/WebSockets_API">WebSockets</a>, and data storage mechanisms like <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a>. See <a href="/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers">Functions and classes available to workers</a> for more details.</p> <p>Data is sent between workers and the main thread via a system of messages — both sides send their messages using the <code>postMessage()</code> method, and respond to messages via the <code>onmessage</code> event handler (the message is contained within the <a href="/en-US/docs/Web/API/Worker/message_event" title="message"><code>message</code></a> event's data attribute). The data is copied rather than shared.</p> <p>Workers may in turn spawn new workers, as long as those workers are hosted within the same <a href="/en-US/docs/Glossary/Origin">origin</a> as the parent page.</p> <p>In addition, workers can make network requests using the <a href="/en-US/docs/Web/API/WorkerGlobalScope/fetch" title="fetch()"><code>fetch()</code></a> or <a href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> APIs (although note that the <a href="/en-US/docs/Web/API/XMLHttpRequest/responseXML" title="responseXML"><code>responseXML</code></a> attribute of <code>XMLHttpRequest</code> will always be <code>null</code>).</p></div></section><section aria-labelledby="dedicated_workers"><h2 id="dedicated_workers"><a href="#dedicated_workers">Dedicated workers</a></h2><div class="section-content"><p>As mentioned above, a dedicated worker is only accessible by the script that called it. In this section we'll discuss the JavaScript found in our <a href="https://github.com/mdn/dom-examples/tree/main/web-workers/simple-web-worker" class="external" target="_blank">Basic dedicated worker example</a> (<a href="https://mdn.github.io/dom-examples/web-workers/simple-web-worker/" class="external" target="_blank">run dedicated worker</a>): This allows you to enter two numbers to be multiplied together. The numbers are sent to a dedicated worker, multiplied together, and the result is returned to the page and displayed.</p> <p>This example is rather trivial, but we decided to keep it simple while introducing you to basic worker concepts. More advanced details are covered later on in the article.</p></div></section><section aria-labelledby="worker_feature_detection"><h3 id="worker_feature_detection"><a href="#worker_feature_detection">Worker feature detection</a></h3><div class="section-content"><p>For slightly more controlled error handling and backwards compatibility, it is a good idea to wrap your worker accessing code in the following (<a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/main.js" class="external" target="_blank">main.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>if (window.Worker) { // … } </code></pre></div></div></section><section aria-labelledby="spawning_a_dedicated_worker"><h3 id="spawning_a_dedicated_worker"><a href="#spawning_a_dedicated_worker">Spawning a dedicated worker</a></h3><div class="section-content"><p>Creating a new worker is simple. All you need to do is call the <a href="/en-US/docs/Web/API/Worker/Worker" title="Worker()"><code>Worker()</code></a> constructor, specifying the URI of a script to execute in the worker thread (<a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/main.js" class="external" target="_blank">main.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const myWorker = new Worker("worker.js"); </code></pre></div> <div class="notecard note"> <p><strong>Note:</strong> Bundlers, including <a href="https://webpack.js.org/guides/web-workers/" class="external" target="_blank">webpack</a>, <a href="https://vite.dev/guide/features.html#web-workers" class="external" target="_blank">Vite</a>, and <a href="https://parceljs.org/languages/javascript/#web-workers" class="external" target="_blank">Parcel</a>, recommend passing URLs that are resolved relative to <a href="/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#url"><code>import.meta.url</code></a> to the <code>Worker()</code> constructor. For example:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const myWorker = new Worker(new URL("worker.js", import.meta.url)); </code></pre></div> <p>This way, the path is relative to the current script instead of the current HTML page, which allows the bundler to safely do optimizations like renaming (because otherwise the <code>worker.js</code> URL may point to a file not controlled by the bundler, so it cannot make any assumptions).</p> </div></div></section><section aria-labelledby="sending_messages_to_and_from_a_dedicated_worker"><h3 id="sending_messages_to_and_from_a_dedicated_worker"><a href="#sending_messages_to_and_from_a_dedicated_worker">Sending messages to and from a dedicated worker</a></h3><div class="section-content"><p>The magic of workers happens via the <a href="/en-US/docs/Web/API/Worker/postMessage" title="postMessage()"><code>postMessage()</code></a> method and the <a href="/en-US/docs/Web/API/Worker/message_event" title="onmessage"><code>onmessage</code></a> event handler. When you want to send a message to the worker, you post messages to it like this (<a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/main.js" class="external" target="_blank">main.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>first.onchange = () => { myWorker.postMessage([first.value, second.value]); console.log("Message posted to worker"); }; second.onchange = () => { myWorker.postMessage([first.value, second.value]); console.log("Message posted to worker"); }; </code></pre></div> <p>So here we have two <a href="/en-US/docs/Web/HTML/Element/input"><code><input></code></a> elements represented by the variables <code>first</code> and <code>second</code>; when the value of either is changed, <code>myWorker.postMessage([first.value,second.value])</code> is used to send the value inside both to the worker, as an array. You can send pretty much anything you like in the message.</p> <p>In the worker, we can respond when the message is received by writing an event handler block like this (<a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/worker.js" class="external" target="_blank">worker.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>onmessage = (e) => { console.log("Message received from main script"); const workerResult = `Result: ${e.data[0] * e.data[1]}`; console.log("Posting message back to main script"); postMessage(workerResult); }; </code></pre></div> <p>The <code>onmessage</code> handler allows us to run some code whenever a message is received, with the message itself being available in the <code>message</code> event's <code>data</code> attribute. Here we multiply together the two numbers then use <code>postMessage()</code> again, to post the result back to the main thread.</p> <p>Back in the main thread, we use <code>onmessage</code> again, to respond to the message sent back from the worker:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>myWorker.onmessage = (e) => { result.textContent = e.data; console.log("Message received from worker"); }; </code></pre></div> <p>Here we grab the message event data and set it as the <code>textContent</code> of the result paragraph, so the user can see the result of the calculation.</p> <div class="notecard note"> <p><strong>Note:</strong> Notice that <code>onmessage</code> and <code>postMessage()</code> need to be hung off the <code>Worker</code> object when used in the main script thread, but not when used in the worker. This is because, inside the worker, the worker is effectively the global scope.</p> </div> <div class="notecard note"> <p><strong>Note:</strong> When a message is passed between the main thread and worker, it is copied or "transferred" (moved), not shared. Read <a href="#transferring_data_to_and_from_workers_further_details">Transferring data to and from workers: further details</a> for a much more thorough explanation.</p> </div></div></section><section aria-labelledby="terminating_a_worker"><h3 id="terminating_a_worker"><a href="#terminating_a_worker">Terminating a worker</a></h3><div class="section-content"><p>If you need to immediately terminate a running worker from the main thread, you can do so by calling the worker's <a href="/en-US/docs/Web/API/Worker" title="terminate"><code>terminate</code></a> method:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>myWorker.terminate(); </code></pre></div> <p>The worker thread is killed immediately.</p></div></section><section aria-labelledby="handling_errors"><h3 id="handling_errors"><a href="#handling_errors">Handling errors</a></h3><div class="section-content"><p>When a runtime error occurs in the worker, its <code>onerror</code> event handler is called. It receives an event named <code>error</code> which implements the <code>ErrorEvent</code> interface.</p> <p>The event doesn't bubble and is cancelable; to prevent the default action from taking place, the worker can call the error event's <a href="/en-US/docs/Web/API/Event/preventDefault"><code>preventDefault()</code></a> method.</p> <p>The error event has the following three fields that are of interest:</p> <dl> <dt id="message"><a href="#message"><code>message</code></a></dt> <dd> <p>A human-readable error message.</p> </dd> <dt id="filename"><a href="#filename"><code>filename</code></a></dt> <dd> <p>The name of the script file in which the error occurred.</p> </dd> <dt id="lineno"><a href="#lineno"><code>lineno</code></a></dt> <dd> <p>The line number of the script file on which the error occurred.</p> </dd> </dl></div></section><section aria-labelledby="spawning_subworkers"><h3 id="spawning_subworkers"><a href="#spawning_subworkers">Spawning subworkers</a></h3><div class="section-content"><p>Workers may spawn more workers if they wish. So-called sub-workers must be hosted within the same origin as the parent page. Also, the URIs for subworkers are resolved relative to the parent worker's location rather than that of the owning page. This makes it easier for workers to keep track of where their dependencies are.</p></div></section><section aria-labelledby="importing_scripts_and_libraries"><h3 id="importing_scripts_and_libraries"><a href="#importing_scripts_and_libraries">Importing scripts and libraries</a></h3><div class="section-content"><p>Worker threads have access to a global function, <code>importScripts()</code>, which lets them import scripts. It accepts zero or more URIs as parameters to resources to import; all the following examples are valid:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>importScripts(); /* imports nothing */ importScripts("foo.js"); /* imports just "foo.js" */ importScripts("foo.js", "bar.js"); /* imports two scripts */ importScripts( "//example.com/hello.js", ); /* You can import scripts from other origins */ </code></pre></div> <p>The browser loads each listed script and executes it. Any global objects from each script may then be used by the worker. If the script can't be loaded, <code>NETWORK_ERROR</code> is thrown, and subsequent code will not be executed. Previously executed code (including code deferred using <a href="/en-US/docs/Web/API/WorkerGlobalScope/setTimeout" title="setTimeout()"><code>setTimeout()</code></a>) will still be functional though. Function declarations <strong>after</strong> the <code>importScripts()</code> method are also kept, since these are always evaluated before the rest of the code.</p> <div class="notecard note"> <p><strong>Note:</strong> Scripts may be downloaded in any order, but will be executed in the order in which you pass the filenames into <code>importScripts()</code>. This is done synchronously; <code>importScripts()</code> does not return until all the scripts have been loaded and executed.</p> </div></div></section><section aria-labelledby="shared_workers"><h2 id="shared_workers"><a href="#shared_workers">Shared workers</a></h2><div class="section-content"><p>A shared worker is accessible by multiple scripts — even if they are being accessed by different windows, iframes or even workers. In this section we'll discuss the JavaScript found in our <a href="https://github.com/mdn/dom-examples/tree/main/web-workers/simple-shared-worker" class="external" target="_blank">Basic shared worker example</a> (<a href="https://mdn.github.io/dom-examples/web-workers/simple-shared-worker/" class="external" target="_blank">run shared worker</a>): This is very similar to the basic dedicated worker example, except that it has two functions available handled by different script files: <em>multiplying two numbers</em>, or <em>squaring a number</em>. Both scripts use the same worker to do the actual calculation required.</p> <p>Here we'll concentrate on the differences between dedicated and shared workers. Note that in this example we have two HTML pages, each with JavaScript applied that uses the same single worker file.</p> <div class="notecard note"> <p><strong>Note:</strong> If SharedWorker can be accessed from several browsing contexts, all those browsing contexts must share the exact same origin (same protocol, host, and port).</p> </div> <div class="notecard note"> <p><strong>Note:</strong> In Firefox, shared workers cannot be shared between documents loaded in private and non-private windows (<a href="https://bugzil.la/1177621" class="external" target="_blank">Firefox bug 1177621</a>).</p> </div></div></section><section aria-labelledby="spawning_a_shared_worker"><h3 id="spawning_a_shared_worker"><a href="#spawning_a_shared_worker">Spawning a shared worker</a></h3><div class="section-content"><p>Spawning a new shared worker is pretty much the same as with a dedicated worker, but with a different constructor name (see <a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/index.html" class="external" target="_blank">index.html</a> and <a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/index2.html" class="external" target="_blank">index2.html</a>) — each one has to spin up the worker using code like the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const myWorker = new SharedWorker("worker.js"); </code></pre></div> <p>One big difference is that with a shared worker you have to communicate via a <code>port</code> object — an explicit port is opened that the scripts can use to communicate with the worker (this is done implicitly in the case of dedicated workers).</p> <p>The port connection needs to be started either implicitly by use of the <code>onmessage</code> event handler or explicitly with the <code>start()</code> method before any messages can be posted. Calling <code>start()</code> is only needed if the <code>message</code> event is wired up via the <code>addEventListener()</code> method.</p> <div class="notecard note"> <p><strong>Note:</strong> When using the <code>start()</code> method to open the port connection, it needs to be called from both the parent thread and the worker thread if two-way communication is needed.</p> </div></div></section><section aria-labelledby="sending_messages_to_and_from_a_shared_worker"><h3 id="sending_messages_to_and_from_a_shared_worker"><a href="#sending_messages_to_and_from_a_shared_worker">Sending messages to and from a shared worker</a></h3><div class="section-content"><p>Now messages can be sent to the worker as before, but the <code>postMessage()</code> method has to be invoked through the port object (again, you'll see similar constructs in both <a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/multiply.js" class="external" target="_blank">multiply.js</a> and <a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/square.js" class="external" target="_blank">square.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>squareNumber.onchange = () => { myWorker.port.postMessage([squareNumber.value, squareNumber.value]); console.log("Message posted to worker"); }; </code></pre></div> <p>Now, on to the worker. There is a bit more complexity here as well (<a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/worker.js" class="external" target="_blank">worker.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>onconnect = (e) => { const port = e.ports[0]; port.onmessage = (e) => { const workerResult = `Result: ${e.data[0] * e.data[1]}`; port.postMessage(workerResult); }; }; </code></pre></div> <p>First, we use an <code>onconnect</code> handler to fire code when a connection to the port happens (i.e. when the <code>onmessage</code> event handler in the parent thread is set up, or when the <code>start()</code> method is explicitly called in the parent thread).</p> <p>We use the <code>ports</code> attribute of this event object to grab the port and store it in a variable.</p> <p>Next, we add an <code>onmessage</code> handler on the port to do the calculation and return the result to the main thread. Setting up this <code>onmessage</code> handler in the worker thread also implicitly opens the port connection back to the parent thread, so the call to <code>port.start()</code> is not actually needed, as noted above.</p> <p>Finally, back in the main script, we deal with the message (again, you'll see similar constructs in both <a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/multiply.js" class="external" target="_blank">multiply.js</a> and <a href="https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/square.js" class="external" target="_blank">square.js</a>):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>myWorker.port.onmessage = (e) => { result2.textContent = e.data; console.log("Message received from worker"); }; </code></pre></div> <p>When a message comes back through the port from the worker, we insert the calculation result inside the appropriate result paragraph.</p></div></section><section aria-labelledby="about_thread_safety"><h2 id="about_thread_safety"><a href="#about_thread_safety">About thread safety</a></h2><div class="section-content"><p>The <a href="/en-US/docs/Web/API/Worker"><code>Worker</code></a> interface spawns real OS-level threads, and mindful programmers may be concerned that concurrency can cause "interesting" effects in your code if you aren't careful.</p> <p>However, since web workers have carefully controlled communication points with other threads, it's actually very hard to cause concurrency problems. There's no access to non-threadsafe components or the DOM. And you have to pass specific data in and out of a thread through serialized objects. So you have to work really hard to cause problems in your code.</p></div></section><section aria-labelledby="content_security_policy"><h2 id="content_security_policy"><a href="#content_security_policy">Content security policy</a></h2><div class="section-content"><p>Workers are considered to have their own execution context, distinct from the document that created them. For this reason they are, in general, not governed by the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy">content security policy</a> of the document (or parent worker) that created them. So for example, suppose a document is served with the following header:</p> <div class="code-example"><div class="example-header"><span class="language-name">http</span></div><pre class="brush: http notranslate"><code>Content-Security-Policy: script-src 'self' </code></pre></div> <p>Among other things, this will prevent any scripts it includes from using <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval"><code>eval()</code></a>. However, if the script constructs a worker, code running in the worker's context <em>will</em> be allowed to use <code>eval()</code>.</p> <p>To specify a content security policy for the worker, set a <a href="/en-US/docs/Web/HTTP/Headers/Content-Security-Policy">Content-Security-Policy</a> response header for the request which delivered the worker script itself.</p> <p>The exception to this is if the worker script's origin is a globally unique identifier (for example, if its URL has a scheme of data or blob). In this case, the worker does inherit the CSP of the document or worker that created it.</p></div></section><section aria-labelledby="transferring_data_to_and_from_workers_further_details"><h2 id="transferring_data_to_and_from_workers_further_details"><a href="#transferring_data_to_and_from_workers_further_details">Transferring data to and from workers: further details</a></h2><div class="section-content"><p>Data passed between the main page and workers is <strong>copied</strong>, not shared. Objects are serialized as they're handed to the worker, and subsequently, de-serialized on the other end. The page and worker <strong>do not share the same instance</strong>, so the end result is that <strong>a duplicate</strong> is created on each end. Most browsers implement this feature as <a href="/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm">structured cloning</a>.</p> <p>To illustrate this, let's create a function named <code>emulateMessage()</code>, which will simulate the behavior of a value that is <em>cloned and not shared</em> during the passage from a <code>worker</code> to the main page or vice versa:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>function emulateMessage(vVal) { return eval(`(${JSON.stringify(vVal)})`); } // Tests // test #1 const example1 = new Number(3); console.log(typeof example1); // object console.log(typeof emulateMessage(example1)); // number // test #2 const example2 = true; console.log(typeof example2); // boolean console.log(typeof emulateMessage(example2)); // boolean // test #3 const example3 = new String("Hello World"); console.log(typeof example3); // object console.log(typeof emulateMessage(example3)); // string // test #4 const example4 = { name: "Carina Anand", age: 43, }; console.log(typeof example4); // object console.log(typeof emulateMessage(example4)); // object // test #5 function Animal(type, age) { this.type = type; this.age = age; } const example5 = new Animal("Cat", 3); alert(example5.constructor); // Animal alert(emulateMessage(example5).constructor); // Object </code></pre></div> <p>A value that is cloned and not shared is called <em>message</em>. As you will probably know by now, <em>messages</em> can be sent to and from the main thread by using <code>postMessage()</code>, and the <code>message</code> event's <a href="/en-US/docs/Web/API/MessageEvent/data" title="data"><code>data</code></a> attribute contains data passed back from the worker.</p> <p><strong>example.html</strong>: (the main page):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const myWorker = new Worker("my_task.js"); myWorker.onmessage = (event) => { console.log(`Worker said : ${event.data}`); }; myWorker.postMessage("ali"); </code></pre></div> <p><strong>my_task.js</strong> (the worker):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>postMessage("I'm working before postMessage('ali')."); onmessage = (event) => { postMessage(`Hi, ${event.data}`); }; </code></pre></div> <p>The <a href="/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm">structured cloning</a> algorithm can accept JSON and a few things that JSON can't — like circular references.</p></div></section><section aria-labelledby="passing_data_examples"><h3 id="passing_data_examples"><a href="#passing_data_examples">Passing data examples</a></h3><div class="section-content"><h4 id="example_1_advanced_passing_json_data_and_creating_a_switching_system">Example 1: Advanced passing JSON Data and creating a switching system</h4> <p>If you have to pass some complex data and have to call many different functions both on the main page and in the Worker, you can create a system which groups everything together.</p> <p>First, we create a <code>QueryableWorker</code> class that takes the URL of the worker, a default listener, and an error handler, and this class is going to keep track of a list of listeners and help us communicate with the worker:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>function QueryableWorker(url, defaultListener, onError) { const instance = this; const worker = new Worker(url); const listeners = {}; this.defaultListener = defaultListener ?? (() => {}); if (onError) { worker.onerror = onError; } this.postMessage = (message) => { worker.postMessage(message); }; this.terminate = () => { worker.terminate(); }; } </code></pre></div> <p>Then we add the methods of adding/removing listeners:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>this.addListeners = (name, listener) => { listeners[name] = listener; }; this.removeListeners = (name) => { delete listeners[name]; }; </code></pre></div> <p>Here we let the worker handle two simple operations for illustration: getting the difference of two numbers and making an alert after three seconds. In order to achieve that we first implement a <code>sendQuery</code> method which queries if the worker actually has the corresponding methods to do what we want.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// This functions takes at least one argument, the method name we want to query. // Then we can pass in the arguments that the method needs. this.sendQuery = (queryMethod, ...queryMethodArguments) => { if (!queryMethod) { throw new TypeError( "QueryableWorker.sendQuery takes at least one argument", ); } worker.postMessage({ queryMethod, queryMethodArguments, }); }; </code></pre></div> <p>We finish QueryableWorker with the <code>onmessage</code> method. If the worker has the corresponding methods we queried, it should return the name of the corresponding listener and the arguments it needs, we just need to find it in <code>listeners</code>.:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>worker.onmessage = (event) => { if ( event.data instanceof Object && Object.hasOwn(event.data, "queryMethodListener") && Object.hasOwn(event.data, "queryMethodArguments") ) { listeners[event.data.queryMethodListener].apply( instance, event.data.queryMethodArguments, ); } else { this.defaultListener.call(instance, event.data); } }; </code></pre></div> <p>Now onto the worker. First we need to have the methods to handle the two simple operations:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const queryableFunctions = { getDifference(a, b) { reply("printStuff", a - b); }, waitSomeTime() { setTimeout(() => { reply("doAlert", 3, "seconds"); }, 3000); }, }; function reply(queryMethodListener, ...queryMethodArguments) { if (!queryMethodListener) { throw new TypeError("reply - takes at least one argument"); } postMessage({ queryMethodListener, queryMethodArguments, }); } /* This method is called when main page calls QueryWorker's postMessage method directly*/ function defaultReply(message) { // do something } </code></pre></div> <p>And the <code>onmessage</code> method is now trivial:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>onmessage = (event) => { if ( event.data instanceof Object && Object.hasOwn(event.data, "queryMethod") && Object.hasOwn(event.data, "queryMethodArguments") ) { queryableFunctions[event.data.queryMethod].apply( self, event.data.queryMethodArguments, ); } else { defaultReply(event.data); } }; </code></pre></div> <p>Here are the full implementation:</p> <p><strong>example.html</strong> (the main page):</p> <div class="code-example"><div class="example-header"><span class="language-name">html</span></div><pre class="brush: html notranslate"><code><!doctype html> <html lang="en-US"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width" /> <title>MDN Example - Queryable worker</title> <script type="text/javascript"> // QueryableWorker instances methods: // * sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc.): calls a Worker's queryable function // * postMessage(string or JSON Data): see Worker.prototype.postMessage() // * terminate(): terminates the Worker // * addListener(name, function): adds a listener // * removeListener(name): removes a listener // QueryableWorker instances properties: // * defaultListener: the default listener executed only when the Worker calls the postMessage() function directly function QueryableWorker(url, defaultListener, onError) { const instance = this; const worker = new Worker(url); const listeners = {}; this.defaultListener = defaultListener ?? (() => {}); if (onError) { worker.onerror = onError; } this.postMessage = (message) => { worker.postMessage(message); }; this.terminate = () => { worker.terminate(); }; this.addListener = (name, listener) => { listeners[name] = listener; }; this.removeListener = (name) => { delete listeners[name]; }; // This functions takes at least one argument, the method name we want to query. // Then we can pass in the arguments that the method needs. this.sendQuery = (queryMethod, ...queryMethodArguments) => { if (!queryMethod) { throw new TypeError( "QueryableWorker.sendQuery takes at least one argument", ); } worker.postMessage({ queryMethod, queryMethodArguments, }); }; worker.onmessage = (event) => { if ( event.data instanceof Object && Object.hasOwn(event.data, "queryMethodListener") && Object.hasOwn(event.data, "queryMethodArguments") ) { listeners[event.data.queryMethodListener].apply( instance, event.data.queryMethodArguments, ); } else { this.defaultListener.call(instance, event.data); } }; } // your custom "queryable" worker const myTask = new QueryableWorker("my_task.js"); // your custom "listeners" myTask.addListener("printStuff", (result) => { document .getElementById("firstLink") .parentNode.appendChild( document.createTextNode(`The difference is ${result}!`), ); }); myTask.addListener("doAlert", (time, unit) => { alert(`Worker waited for ${time} ${unit} :-)`); }); </script> </head> <body> <ul> <li> <a id="firstLink" href="javascript:myTask.sendQuery('getDifference', 5, 3);" >What is the difference between 5 and 3?</a > </li> <li> <a href="javascript:myTask.sendQuery('waitSomeTime');" >Wait 3 seconds</a > </li> <li> <a href="javascript:myTask.terminate();">terminate() the Worker</a> </li> </ul> </body> </html> </code></pre></div> <p><strong>my_task.js</strong> (the worker):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const queryableFunctions = { // example #1: get the difference between two numbers: getDifference(minuend, subtrahend) { reply("printStuff", minuend - subtrahend); }, // example #2: wait three seconds waitSomeTime() { setTimeout(() => { reply("doAlert", 3, "seconds"); }, 3000); }, }; // system functions function defaultReply(message) { // your default PUBLIC function executed only when main page calls the queryableWorker.postMessage() method directly // do something } function reply(queryMethodListener, ...queryMethodArguments) { if (!queryMethodListener) { throw new TypeError("reply - not enough arguments"); } postMessage({ queryMethodListener, queryMethodArguments, }); } onmessage = (event) => { if ( event.data instanceof Object && Object.hasOwn(event.data, "queryMethod") && Object.hasOwn(event.data, "queryMethodArguments") ) { queryableFunctions[event.data.queryMethod].apply( self, event.data.queryMethodArguments, ); } else { defaultReply(event.data); } }; </code></pre></div> <p>It is possible to switch the content of each mainpage -> worker and worker -> mainpage message. And the property names "queryMethod", "queryMethodListeners", "queryMethodArguments" can be anything as long as they are consistent in <code>QueryableWorker</code> and the <code>worker</code>.</p></div></section><section aria-labelledby="passing_data_by_transferring_ownership_transferable_objects"><h3 id="passing_data_by_transferring_ownership_transferable_objects"><a href="#passing_data_by_transferring_ownership_transferable_objects">Passing data by transferring ownership (transferable objects)</a></h3><div class="section-content"><p>Modern browsers contain an additional way to pass certain types of objects to or from a worker with high performance. <a href="/en-US/docs/Web/API/Web_Workers_API/Transferable_objects">Transferable objects</a> are transferred from one context to another with a zero-copy operation, which results in a vast performance improvement when sending large data sets.</p> <p>For example, when transferring an <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer"><code>ArrayBuffer</code></a> from your main app to a worker script, the original <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer"><code>ArrayBuffer</code></a> is cleared and no longer usable. Its content is (quite literally) transferred to the worker context.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Create a 32MB "file" and fill it with consecutive values from 0 to 255 – 32MB = 1024 * 1024 * 32 const uInt8Array = new Uint8Array(1024 * 1024 * 32).map((v, i) => i); worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]); </code></pre></div></div></section><section aria-labelledby="embedded_workers"><h2 id="embedded_workers"><a href="#embedded_workers">Embedded workers</a></h2><div class="section-content"><p>There is not an "official" way to embed the code of a worker within a web page, like <a href="/en-US/docs/Web/HTML/Element/script"><code><script></code></a> elements do for normal scripts. But a <a href="/en-US/docs/Web/HTML/Element/script"><code><script></code></a> element that does not have a <code>src</code> attribute and has a <code>type</code> attribute that does not identify an executable MIME type can be considered a data block element that JavaScript could use. "Data blocks" is a more general feature of HTML that can carry almost any textual data. So, a worker could be embedded in this way:</p> <div class="code-example"><div class="example-header"><span class="language-name">html</span></div><pre class="brush: html notranslate"><code><!doctype html> <html lang="en-US"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width" /> <title>MDN Example - Embedded worker</title> <script type="text/js-worker"> // This script WON'T be parsed by JS engines because its MIME type is text/js-worker. const myVar = 'Hello World!'; // Rest of your worker code goes here. </script> <script> // This script WILL be parsed by JS engines because its MIME type is text/javascript. function pageLog(sMsg) { // Use a fragment: browser will only render/reflow once. const frag = document.createDocumentFragment(); frag.appendChild(document.createTextNode(sMsg)); frag.appendChild(document.createElement("br")); document.querySelector("#logDisplay").appendChild(frag); } </script> <script type="text/js-worker"> // This script WON'T be parsed by JS engines because its MIME type is text/js-worker. onmessage = (event) => { postMessage(myVar); }; // Rest of your worker code goes here. </script> <script> // This script WILL be parsed by JS engines because its MIME type is text/javascript. // In the past blob builder existed, but now we use Blob const blob = new Blob( Array.prototype.map.call( document.querySelectorAll("script[type='text\/js-worker']"), (script) => script.textContent, ), { type: "text/javascript" }, ); // Creating a new document.worker property containing all our "text/js-worker" scripts. document.worker = new Worker(window.URL.createObjectURL(blob)); document.worker.onmessage = (event) => { pageLog(`Received: ${event.data}`); }; // Start the worker. window.onload = () => { document.worker.postMessage(""); }; </script> </head> <body> <div id="logDisplay"></div> </body> </html> </code></pre></div> <p>The embedded worker is now nested into a new custom <code>document.worker</code> property.</p> <p>It is also worth noting that you can also convert a function into a Blob, then generate an object URL from that blob. For example:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>function fn2workerURL(fn) { const blob = new Blob([`(${fn.toString()})()`], { type: "text/javascript" }); return URL.createObjectURL(blob); } </code></pre></div></div></section><section aria-labelledby="further_examples"><h2 id="further_examples"><a href="#further_examples">Further examples</a></h2><div class="section-content"><p>This section provides further examples of how to use web workers.</p></div></section><section aria-labelledby="performing_computations_in_the_background"><h3 id="performing_computations_in_the_background"><a href="#performing_computations_in_the_background">Performing computations in the background</a></h3><div class="section-content"><p>Workers are mainly useful for allowing your code to perform processor-intensive calculations without blocking the user interface thread. In this example, a worker is used to calculate Fibonacci numbers.</p> <h4 id="the_javascript_code">The JavaScript code</h4> <p>The following JavaScript code is stored in the "fibonacci.js" file referenced by the HTML in the next section.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>self.onmessage = (event) => { const userNum = Number(event.data); self.postMessage(fibonacci(userNum)); }; function fibonacci(num) { let a = 1; let b = 0; while (num > 0) { [a, b] = [a + b, a]; num--; } return b; } </code></pre></div> <p>The worker sets the property <code>onmessage</code> to a function which will receive messages sent when the worker object's <code>postMessage()</code> is called. This performs the math and eventually returns the result back to the main thread.</p> <h4 id="the_html_code">The HTML code</h4> <div class="code-example"><div class="example-header"><span class="language-name">html</span></div><pre class="brush: html notranslate"><code><!doctype html> <html lang="en-US"> <head> <meta charset="UTF-8" /> <title>Fibonacci number generator</title> <style> body { width: 500px; } div, p { margin-bottom: 20px; } </style> </head> <body> <form> <div> <label for="number" >Enter a number that is a zero-based index position in the fibonacci sequence to see what number is in that position. For example, enter 6 and you'll get a result of 8 — the fibonacci number at index position 6 is 8.</label > <input type="number" id="number" /> </div> <div> <input type="submit" /> </div> </form> <p id="result"></p> <script> const form = document.querySelector("form"); const input = document.querySelector('input[type="number"]'); const result = document.querySelector("p#result"); const worker = new Worker("fibonacci.js"); worker.onmessage = (event) => { result.textContent = event.data; console.log(`Got: ${event.data}`); }; worker.onerror = (error) => { console.log(`Worker error: ${error.message}`); throw error; }; form.onsubmit = (e) => { e.preventDefault(); worker.postMessage(input.value); input.value = ""; }; </script> </body> </html> </code></pre></div> <p>The web page creates a <code><p></code> element with the ID <code>result</code>, which gets used to display the result, then spawns the worker. After spawning the worker, the <code>onmessage</code> handler is configured to display the results by setting the contents of the <code><p></code> element, and the <code>onerror</code> handler is set to log the error message to the devtools console.</p> <p>Finally, a message is sent to the worker to start it.</p> <p><a href="https://mdn.github.io/dom-examples/web-workers/fibonacci-worker/" class="external" target="_blank">Try this example live</a>.</p></div></section><section aria-labelledby="dividing_tasks_among_multiple_workers"><h3 id="dividing_tasks_among_multiple_workers"><a href="#dividing_tasks_among_multiple_workers">Dividing tasks among multiple workers</a></h3><div class="section-content"><p>As multicore computers become increasingly common, it's often useful to divide computationally complex tasks among multiple workers, which may then perform those tasks on multiple-processor cores.</p></div></section><section aria-labelledby="other_types_of_workers"><h2 id="other_types_of_workers"><a href="#other_types_of_workers">Other types of workers</a></h2><div class="section-content"><p>In addition to dedicated and shared web workers, there are other types of workers available:</p> <ul> <li><a href="/en-US/docs/Web/API/Service_Worker_API">ServiceWorkers</a> essentially act as proxy servers that sit between web applications, and the browser and network (when available). They are intended to (amongst other things) enable the creation of effective offline experiences, intercepting network requests and taking appropriate action based on whether the network is available and updated assets reside on the server. They will also allow access to push notifications and background sync APIs.</li> <li><a href="/en-US/docs/Web/API/Web_Audio_API#audio_processing_in_javascript">Audio Worklet</a> provide the ability for direct scripted audio processing to be done in a worklet (a lightweight version of worker) context.</li> </ul></div></section><section aria-labelledby="debugging_worker_threads"><h2 id="debugging_worker_threads"><a href="#debugging_worker_threads">Debugging worker threads</a></h2><div class="section-content"><p>Most browsers enable you to debug web workers in their JavaScript debuggers in <em>exactly the same way</em> as debugging the main thread! For example, both Firefox and Chrome list JavaScript source files for both the main thread and active worker threads, and all of these files can be opened to set breakpoints and logpoints.</p> <p>To learn how to debug web workers, see the documentation for each browser's JavaScript debugger:</p> <ul> <li><a href="https://developer.chrome.com/docs/devtools/sources" class="external" target="_blank">Chrome Sources panel</a></li> <li><a href="https://firefox-source-docs.mozilla.org/devtools-user/debugger/" class="external" target="_blank">Firefox JavaScript Debugger</a></li> </ul></div></section><section aria-labelledby="functions_and_interfaces_available_in_workers"><h2 id="functions_and_interfaces_available_in_workers"><a href="#functions_and_interfaces_available_in_workers">Functions and interfaces available in workers</a></h2><div class="section-content"><p>You can use most standard JavaScript features inside a web worker, including:</p> <ul> <li><a href="/en-US/docs/Web/API/Navigator"><code>Navigator</code></a></li> <li><a href="/en-US/docs/Web/API/WorkerGlobalScope/fetch" title="fetch()"><code>fetch()</code></a></li> <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array"><code>Array</code></a>, <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date"><code>Date</code></a>, <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math"><code>Math</code></a>, and <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><code>String</code></a></li> <li><a href="/en-US/docs/Web/API/WorkerGlobalScope/setTimeout" title="setTimeout()"><code>setTimeout()</code></a> and <a href="/en-US/docs/Web/API/WorkerGlobalScope/setInterval" title="setInterval()"><code>setInterval()</code></a></li> </ul> <p>The main thing you <em>can't</em> do in a Worker is directly affect the parent page. This includes manipulating the DOM and using that page's objects. You have to do it indirectly, by sending a message back to the main script via <a href="/en-US/docs/Web/API/DedicatedWorkerGlobalScope/postMessage"><code>DedicatedWorkerGlobalScope.postMessage()</code></a>, then doing the changes in event handler.</p> <div class="notecard note"> <p><strong>Note:</strong> You can test whether a method is available to workers using the site: <a href="https://worker-playground.glitch.me/" class="external" target="_blank">https://worker-playground.glitch.me/</a>. For example, if you enter <a href="/en-US/docs/Web/API/EventSource"><code>EventSource</code></a> into the site on Firefox 84 you'll see that this is not supported in service workers, but is in dedicated and shared workers.</p> </div> <div class="notecard note"> <p><strong>Note:</strong> For a complete list of functions available to workers, see <a href="/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers">Functions and interfaces available to workers</a>.</p> </div></div></section><h2 id="specifications"><a href="#specifications">Specifications</a></h2><table class="standard-table"><thead><tr><th scope="col">Specification</th></tr></thead><tbody><tr><td><a href="https://html.spec.whatwg.org/multipage/#workers">HTML Standard<!-- --> <br/><small># <!-- -->workers</small></a></td></tr></tbody></table><section aria-labelledby="see_also"><h2 id="see_also"><a href="#see_also">See also</a></h2><div class="section-content"><ul> <li><a href="/en-US/docs/Web/API/Worker"><code>Worker</code></a> interface</li> <li><a href="/en-US/docs/Web/API/SharedWorker"><code>SharedWorker</code></a> interface</li> <li><a href="/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers">Functions available to workers</a></li> <li><a href="/en-US/docs/Web/API/OffscreenCanvas"><code>OffscreenCanvas</code></a> interface</li> </ul></div></section></article><aside class="article-footer"><div class="article-footer-inner"><div class="svg-container"><svg xmlns="http://www.w3.org/2000/svg" width="162" height="162" viewBox="0 0 162 162" fill="none" role="none"><mask id="b" fill="#fff"><path d="M97.203 47.04c8.113-7.886 18.004-13.871 28.906-17.492a78 78 0 0 1 33.969-3.39c11.443 1.39 22.401 5.295 32.024 11.411s17.656 14.28 23.476 23.86c5.819 9.579 9.269 20.318 10.083 31.385a69.85 69.85 0 0 1-5.387 32.44c-4.358 10.272-11.115 19.443-19.747 26.801-8.632 7.359-18.908 12.709-30.034 15.637l-6.17-21.698c7.666-2.017 14.746-5.703 20.694-10.773 5.948-5.071 10.603-11.389 13.606-18.467a48.14 48.14 0 0 0 3.712-22.352c-.561-7.625-2.938-15.025-6.948-21.625s-9.544-12.226-16.175-16.44-14.181-6.904-22.065-7.863a53.75 53.75 0 0 0-23.405 2.336c-7.513 2.495-14.327 6.62-19.918 12.053z"></path></mask><path stroke="url(#a)" stroke-dasharray="6, 6" stroke-width="2" d="M97.203 47.04c8.113-7.886 18.004-13.871 28.906-17.492a78 78 0 0 1 33.969-3.39c11.443 1.39 22.401 5.295 32.024 11.411s17.656 14.28 23.476 23.86c5.819 9.579 9.269 20.318 10.083 31.385a69.85 69.85 0 0 1-5.387 32.44c-4.358 10.272-11.115 19.443-19.747 26.801-8.632 7.359-18.908 12.709-30.034 15.637l-6.17-21.698c7.666-2.017 14.746-5.703 20.694-10.773 5.948-5.071 10.603-11.389 13.606-18.467a48.14 48.14 0 0 0 3.712-22.352c-.561-7.625-2.938-15.025-6.948-21.625s-9.544-12.226-16.175-16.44-14.181-6.904-22.065-7.863a53.75 53.75 0 0 0-23.405 2.336c-7.513 2.495-14.327 6.62-19.918 12.053z" mask="url(#b)" style="stroke:url(#a)" transform="translate(-63.992 -25.587)"></path><ellipse cx="8.066" cy="111.597" fill="var(--background-tertiary)" rx="53.677" ry="53.699" transform="matrix(.71707 -.697 .7243 .6895 0 0)"></ellipse><g clip-path="url(#c)" transform="translate(-63.992 -25.587)"><path fill="#9abff5" d="m144.256 137.379 32.906 12.434a4.41 4.41 0 0 1 2.559 5.667l-9.326 24.679a4.41 4.41 0 0 1-5.667 2.559l-8.226-3.108-2.332 6.17c-.466 1.233-.375 1.883-1.609 1.417l-2.253-.527c-.411-.155-.95-.594-1.206-1.161l-4.734-10.484-12.545-4.741a4.41 4.41 0 0 1-2.559-5.667l9.325-24.679a4.41 4.41 0 0 1 5.667-2.559m9.961 29.617 8.227 3.108 3.264-8.638-.498-6.768-4.113-1.555.548 7.258-4.319-1.632zm-12.339-4.663 8.226 3.108 3.264-8.637-.498-6.769-4.113-1.554.548 7.257-4.319-1.632z"></path></g><g clip-path="url(#d)" transform="translate(-63.992 -25.587)"><path fill="#81b0f3" d="M135.35 60.136 86.67 41.654c-3.346-1.27-7.124.428-8.394 3.775L64.414 81.938c-1.27 3.347.428 7.125 3.774 8.395l12.17 4.62-3.465 9.128c-.693 1.826-1.432 2.457.394 3.15l3.014 1.625c.609.231 1.637.274 2.477-.104l15.53-6.983 18.56 7.047c3.346 1.27 7.124-.428 8.395-3.775l13.862-36.51c1.27-3.346-.428-7.124-3.775-8.395M95.261 83.207l-12.17-4.62 4.852-12.779 7.19-7.017 6.085 2.31-7.725 7.51 6.389 2.426zm18.255 6.93-12.17-4.62 4.852-12.778 7.189-7.017 6.085 2.31-7.725 7.51 6.39 2.426z"></path></g><defs><clipPath id="c"><path fill="#fff" d="m198.638 146.586-65.056-24.583-24.583 65.057 65.056 24.582z"></path></clipPath><clipPath id="d"><path fill="#fff" d="m66.438 14.055 96.242 36.54-36.54 96.243-96.243-36.54z"></path></clipPath><linearGradient id="a" x1="97.203" x2="199.995" y1="47.04" y2="152.793" gradientUnits="userSpaceOnUse"><stop stop-color="#086DFC"></stop><stop offset="0.246" stop-color="#2C81FA"></stop><stop offset="0.516" stop-color="#5497F8"></stop><stop offset="0.821" stop-color="#80B0F6"></stop><stop offset="1" stop-color="#9ABFF5"></stop></linearGradient></defs></svg></div><h2>Help improve MDN</h2><fieldset class="feedback"><label>Was this page helpful to you?</label><div class="button-container"><button type="button" class="button primary has-icon yes"><span class="button-wrap"><span class="icon icon-thumbs-up "></span>Yes</span></button><button type="button" class="button primary has-icon no"><span class="button-wrap"><span class="icon icon-thumbs-down "></span>No</span></button></div></fieldset><a class="contribute" href="https://github.com/mdn/content/blob/main/CONTRIBUTING.md" title="This will take you to our contribution guidelines on GitHub." target="_blank" rel="noopener noreferrer">Learn how to contribute</a>.<p class="last-modified-date">This page was last modified on<!-- --> <time dateTime="2024-11-22T16:43:48.000Z">Nov 22, 2024</time> by<!-- --> <a href="/en-US/docs/Web/API/Web_Workers_API/Using_web_workers/contributors.txt" rel="nofollow">MDN contributors</a>.</p><div id="on-github" class="on-github"><a href="https://github.com/mdn/content/blob/main/files/en-us/web/api/web_workers_api/using_web_workers/index.md?plain=1" title="Folder: en-us/web/api/web_workers_api/using_web_workers (Opens in a new tab)" target="_blank" rel="noopener noreferrer">View this page on GitHub</a> <!-- -->•<!-- --> <a href="https://github.com/mdn/content/issues/new?template=page-report.yml&mdn-url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FAPI%2FWeb_Workers_API%2FUsing_web_workers&metadata=%3C%21--+Do+not+make+changes+below+this+line+--%3E%0A%3Cdetails%3E%0A%3Csummary%3EPage+report+details%3C%2Fsummary%3E%0A%0A*+Folder%3A+%60en-us%2Fweb%2Fapi%2Fweb_workers_api%2Fusing_web_workers%60%0A*+MDN+URL%3A+https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FAPI%2FWeb_Workers_API%2FUsing_web_workers%0A*+GitHub+URL%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Fcontent%2Fblob%2Fmain%2Ffiles%2Fen-us%2Fweb%2Fapi%2Fweb_workers_api%2Fusing_web_workers%2Findex.md%0A*+Last+commit%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Fcontent%2Fcommit%2F5f76b99045f87349ed030bbd6a3c2e43badb3c22%0A*+Document+last+modified%3A+2024-11-22T16%3A43%3A48.000Z%0A%0A%3C%2Fdetails%3E" title="This will take you to GitHub to file a new issue." target="_blank" rel="noopener noreferrer">Report a problem with this content</a></div></div></aside></main></div></div><footer id="nav-footer" class="page-footer"><div class="page-footer-grid"><div class="page-footer-logo-col"><a href="/" class="mdn-footer-logo" aria-label="MDN homepage"><svg width="48" height="17" viewBox="0 0 48 17" fill="none" xmlns="http://www.w3.org/2000/svg"><title id="mdn-footer-logo-svg">MDN logo</title><path d="M20.04 16.512H15.504V10.416C15.504 9.488 15.344 8.824 15.024 8.424C14.72 8.024 14.264 7.824 13.656 7.824C12.92 7.824 12.384 8.064 12.048 8.544C11.728 9.024 11.568 9.64 11.568 10.392V14.184H13.008V16.512H8.472V10.416C8.472 9.488 8.312 8.824 7.992 8.424C7.688 8.024 7.232 7.824 6.624 7.824C5.872 7.824 5.336 8.064 5.016 8.544C4.696 9.024 4.536 9.64 4.536 10.392V14.184H6.6V16.512H0V14.184H1.44V8.04H0.024V5.688H4.536V7.32C5.224 6.088 6.32 5.472 7.824 5.472C8.608 5.472 9.328 5.664 9.984 6.048C10.64 6.432 11.096 7.016 11.352 7.8C11.992 6.248 13.168 5.472 14.88 5.472C15.856 5.472 16.72 5.776 17.472 6.384C18.224 6.992 18.6 7.936 18.6 9.216V14.184H20.04V16.512Z" fill="currentColor"></path><path d="M33.6714 16.512H29.1354V14.496C28.8314 15.12 28.3834 15.656 27.7914 16.104C27.1994 16.536 26.4154 16.752 25.4394 16.752C24.0154 16.752 22.8954 16.264 22.0794 15.288C21.2634 14.312 20.8554 12.984 20.8554 11.304C20.8554 9.688 21.2554 8.312 22.0554 7.176C22.8554 6.04 24.0634 5.472 25.6794 5.472C26.5594 5.472 27.2794 5.648 27.8394 6C28.3994 6.352 28.8314 6.8 29.1354 7.344V2.352H26.9754V0H32.2314V14.184H33.6714V16.512ZM29.1354 11.04V10.776C29.1354 9.88 28.8954 9.184 28.4154 8.688C27.9514 8.176 27.3674 7.92 26.6634 7.92C25.9754 7.92 25.3674 8.176 24.8394 8.688C24.3274 9.2 24.0714 10.008 24.0714 11.112C24.0714 12.152 24.3114 12.944 24.7914 13.488C25.2714 14.032 25.8394 14.304 26.4954 14.304C27.3114 14.304 27.9514 13.96 28.4154 13.272C28.8954 12.584 29.1354 11.84 29.1354 11.04Z" fill="currentColor"></path><path d="M47.9589 16.512H41.9829V14.184H43.4229V10.416C43.4229 9.488 43.2629 8.824 42.9429 8.424C42.6389 8.024 42.1829 7.824 41.5749 7.824C40.8389 7.824 40.2709 8.056 39.8709 8.52C39.4709 8.968 39.2629 9.56 39.2469 10.296V14.184H40.6869V16.512H34.7109V14.184H36.1509V8.04H34.5909V5.688H39.2469V7.344C39.9669 6.096 41.1269 5.472 42.7269 5.472C43.7509 5.472 44.6389 5.776 45.3909 6.384C46.1429 6.992 46.5189 7.936 46.5189 9.216V14.184H47.9589V16.512Z" fill="currentColor"></path></svg></a><p>Your blueprint for a better internet.</p><ul class="social-icons"><li><a href="https://mozilla.social/@mdn" target="_blank" rel="me noopener noreferrer"><span class="icon icon-mastodon"></span><span class="visually-hidden">MDN on Mastodon</span></a></li><li><a href="https://twitter.com/mozdevnet" target="_blank" rel="noopener noreferrer"><span class="icon icon-twitter-x"></span><span class="visually-hidden">MDN on X (formerly Twitter)</span></a></li><li><a href="https://github.com/mdn/" target="_blank" rel="noopener noreferrer"><span class="icon icon-github-mark-small"></span><span class="visually-hidden">MDN on GitHub</span></a></li><li><a href="/en-US/blog/rss.xml" target="_blank"><span class="icon icon-feed"></span><span class="visually-hidden">MDN Blog RSS Feed</span></a></li></ul></div><div class="page-footer-nav-col-1"><h2 class="footer-nav-heading">MDN</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a href="/en-US/about">About</a></li><li class="footer-nav-item"><a href="/en-US/blog/">Blog</a></li><li class="footer-nav-item"><a href="https://www.mozilla.org/en-US/careers/listings/?team=ProdOps" target="_blank" rel="noopener noreferrer">Careers</a></li><li class="footer-nav-item"><a href="/en-US/advertising">Advertise with us</a></li></ul></div><div class="page-footer-nav-col-2"><h2 class="footer-nav-heading">Support</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="https://support.mozilla.org/products/mdn-plus">Product help</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/MDN/Community/Issues">Report an issue</a></li></ul></div><div class="page-footer-nav-col-3"><h2 class="footer-nav-heading">Our communities</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/community">MDN Community</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="https://discourse.mozilla.org/c/mdn/236" target="_blank" rel="noopener noreferrer">MDN Forum</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/discord" target="_blank" rel="noopener noreferrer">MDN Chat</a></li></ul></div><div class="page-footer-nav-col-4"><h2 class="footer-nav-heading">Developers</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/Web">Web Technologies</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/Learn">Learn Web Development</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/plus">MDN Plus</a></li><li class="footer-nav-item"><a href="https://hacks.mozilla.org/" target="_blank" rel="noopener noreferrer">Hacks Blog</a></li></ul></div><div class="page-footer-moz"><a href="https://www.mozilla.org/" class="footer-moz-logo-link" target="_blank" rel="noopener noreferrer"><svg width="112" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><title id="mozilla-footer-logo-svg">Mozilla logo</title><path d="M41.753 14.218c-2.048 0-3.324 1.522-3.324 4.157 0 2.423 1.119 4.286 3.29 4.286 2.082 0 3.447-1.678 3.447-4.347 0-2.826-1.522-4.096-3.413-4.096Zm54.89 7.044c0 .901.437 1.618 1.645 1.618 1.427 0 2.949-1.024 3.044-3.352-.649-.095-1.365-.185-2.02-.185-1.426-.005-2.668.397-2.668 1.92Z" fill="currentColor"></path><path d="M0 0v32h111.908V0H0Zm32.56 25.426h-5.87v-7.884c0-2.423-.806-3.352-2.39-3.352-1.924 0-2.702 1.365-2.702 3.324v4.868h1.864v3.044h-5.864v-7.884c0-2.423-.806-3.352-2.39-3.352-1.924 0-2.702 1.365-2.702 3.324v4.868h2.669v3.044H6.642v-3.044h1.863v-7.918H6.642V11.42h5.864v2.11c.839-1.489 2.3-2.39 4.252-2.39 2.02 0 3.878.963 4.566 3.01.778-1.862 2.361-3.01 4.566-3.01 2.512 0 4.812 1.522 4.812 4.84v6.402h1.863v3.044h-.005Zm9.036.307c-4.314 0-7.296-2.635-7.296-7.106 0-4.096 2.484-7.481 7.514-7.481s7.481 3.38 7.481 7.29c0 4.472-3.228 7.297-7.699 7.297Zm22.578-.307H51.942l-.403-2.11 7.7-8.846h-4.376l-.621 2.17-2.888-.313.498-4.907h12.294l.313 2.11-7.767 8.852h4.533l.654-2.172 3.167.308-.872 4.908Zm7.99 0h-4.191v-5.03h4.19v5.03Zm0-8.976h-4.191v-5.03h4.19v5.03Zm2.618 8.976 6.054-21.358h3.945l-6.054 21.358h-3.945Zm8.136 0 6.048-21.358h3.945l-6.054 21.358h-3.939Zm21.486.307c-1.863 0-2.887-1.085-3.072-2.792-.805 1.427-2.232 2.792-4.498 2.792-2.02 0-4.314-1.085-4.314-4.006 0-3.447 3.323-4.253 6.518-4.253.778 0 1.584.034 2.3.124v-.465c0-1.427-.034-3.133-2.3-3.133-.84 0-1.488.061-2.143.402l-.453 1.578-3.195-.34.549-3.224c2.45-.996 3.692-1.27 5.992-1.27 3.01 0 5.556 1.55 5.556 4.75v6.083c0 .805.314 1.085.963 1.085.184 0 .375-.034.587-.095l.034 2.11a5.432 5.432 0 0 1-2.524.654Z" fill="currentColor"></path></svg></a><ul class="footer-moz-list"><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Website Privacy Notice</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/#cookies" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Cookies</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/legal/terms/mozilla" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Legal</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/governance/policies/participation/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Community Participation Guidelines</a></li></ul></div><div class="page-footer-legal"><p id="license" class="page-footer-legal-text">Visit<!-- --> <a href="https://www.mozilla.org" target="_blank" rel="noopener noreferrer">Mozilla Corporation’s</a> <!-- -->not-for-profit parent, the<!-- --> <a target="_blank" rel="noopener noreferrer" href="https://foundation.mozilla.org/">Mozilla Foundation</a>.<br/>Portions of this content are ©1998–<!-- -->2024<!-- --> by individual mozilla.org contributors. Content available under<!-- --> <a href="/en-US/docs/MDN/Writing_guidelines/Attrib_copyright_license">a Creative Commons license</a>.</p></div></div></footer></div><script type="application/json" id="hydration">{"url":"/en-US/docs/Web/API/Web_Workers_API/Using_web_workers","doc":{"isMarkdown":true,"isTranslated":false,"isActive":true,"flaws":{},"title":"Using Web Workers","mdn_url":"/en-US/docs/Web/API/Web_Workers_API/Using_web_workers","locale":"en-US","native":"English (US)","sidebarHTML":"<ol><li class=\"section\"><a href=\"/en-US/docs/Web/API/Web_Workers_API\">Web Workers API</a></li><li class=\"toggle\"><details open=\"\"><summary>Guides</summary><ol><li><em><a href=\"/en-US/docs/Web/API/Web_Workers_API/Using_web_workers\" aria-current=\"page\">Using Web Workers</a></em></li><li><a href=\"/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers\">Functions and classes available to Web Workers</a></li><li><a href=\"/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm\">The structured clone algorithm</a></li><li><a href=\"/en-US/docs/Web/API/Web_Workers_API/Transferable_objects\">Transferable objects</a></li></ol></details></li><li class=\"toggle\"><details open=\"\"><summary>Interfaces</summary><ol><li><a href=\"/en-US/docs/Web/API/DedicatedWorkerGlobalScope\"><code>DedicatedWorkerGlobalScope</code></a></li><li><a href=\"/en-US/docs/Web/API/SharedWorker\"><code>SharedWorker</code></a></li><li><a href=\"/en-US/docs/Web/API/SharedWorkerGlobalScope\"><code>SharedWorkerGlobalScope</code></a></li><li><a href=\"/en-US/docs/Web/API/Worker\"><code>Worker</code></a></li><li><a href=\"/en-US/docs/Web/API/WorkerGlobalScope\"><code>WorkerGlobalScope</code></a></li><li><a href=\"/en-US/docs/Web/API/WorkerLocation\"><code>WorkerLocation</code></a></li><li><a href=\"/en-US/docs/Web/API/WorkerNavigator\"><code>WorkerNavigator</code></a></li></ol></details></li></ol>","sidebarMacro":"DefaultAPISidebar","body":[{"type":"prose","value":{"id":null,"title":null,"isH3":false,"content":"<p>Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can make network requests using the <a href=\"/en-US/docs/Web/API/WorkerGlobalScope/fetch\" title=\"fetch()\"><code>fetch()</code></a> or <a href=\"/en-US/docs/Web/API/XMLHttpRequest\"><code>XMLHttpRequest</code></a> APIs. Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa).</p>\n<p>This article provides a detailed introduction to using web workers.</p>"}},{"type":"prose","value":{"id":"web_workers_api","title":"Web Workers API","isH3":false,"content":"<p>A worker is an object created using a constructor (e.g. <a href=\"/en-US/docs/Web/API/Worker/Worker\" title=\"Worker()\"><code>Worker()</code></a>) that runs a named JavaScript file — this file contains the code that will run in the worker thread; workers run in another global context that is different from the current <a href=\"/en-US/docs/Web/API/Window\"><code>window</code></a>. Thus, using the <a href=\"/en-US/docs/Web/API/Window\"><code>window</code></a> shortcut to get the current global scope (instead of <a href=\"/en-US/docs/Web/API/Window/self\" title=\"self\"><code>self</code></a>) within a <a href=\"/en-US/docs/Web/API/Worker\"><code>Worker</code></a> will return an error.</p>\n<p>The worker context is represented by a <a href=\"/en-US/docs/Web/API/DedicatedWorkerGlobalScope\"><code>DedicatedWorkerGlobalScope</code></a> object in the case of dedicated workers (standard workers that are utilized by a single script; shared workers use <a href=\"/en-US/docs/Web/API/SharedWorkerGlobalScope\"><code>SharedWorkerGlobalScope</code></a>). A dedicated worker is only accessible from the script that first spawned it, whereas shared workers can be accessed from multiple scripts.</p>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> See <a href=\"/en-US/docs/Web/API/Web_Workers_API\">The Web Workers API landing page</a> for reference documentation on workers and additional guides.</p>\n</div>\n<p>You can run whatever code you like inside the worker thread, with some exceptions. For example, you can't directly manipulate the DOM from inside a worker, or use some default methods and properties of the <a href=\"/en-US/docs/Web/API/Window\"><code>window</code></a> object. But you can use a large number of items available under <code>window</code>, including <a href=\"/en-US/docs/Web/API/WebSockets_API\">WebSockets</a>, and data storage mechanisms like <a href=\"/en-US/docs/Web/API/IndexedDB_API\">IndexedDB</a>. See <a href=\"/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers\">Functions and classes available to workers</a> for more details.</p>\n<p>Data is sent between workers and the main thread via a system of messages — both sides send their messages using the <code>postMessage()</code> method, and respond to messages via the <code>onmessage</code> event handler (the message is contained within the <a href=\"/en-US/docs/Web/API/Worker/message_event\" title=\"message\"><code>message</code></a> event's data attribute). The data is copied rather than shared.</p>\n<p>Workers may in turn spawn new workers, as long as those workers are hosted within the same <a href=\"/en-US/docs/Glossary/Origin\">origin</a> as the parent page.</p>\n<p>In addition, workers can make network requests using the <a href=\"/en-US/docs/Web/API/WorkerGlobalScope/fetch\" title=\"fetch()\"><code>fetch()</code></a> or <a href=\"/en-US/docs/Web/API/XMLHttpRequest\"><code>XMLHttpRequest</code></a> APIs (although note that the <a href=\"/en-US/docs/Web/API/XMLHttpRequest/responseXML\" title=\"responseXML\"><code>responseXML</code></a> attribute of <code>XMLHttpRequest</code> will always be <code>null</code>).</p>"}},{"type":"prose","value":{"id":"dedicated_workers","title":"Dedicated workers","isH3":false,"content":"<p>As mentioned above, a dedicated worker is only accessible by the script that called it. In this section we'll discuss the JavaScript found in our <a href=\"https://github.com/mdn/dom-examples/tree/main/web-workers/simple-web-worker\" class=\"external\" target=\"_blank\">Basic dedicated worker example</a> (<a href=\"https://mdn.github.io/dom-examples/web-workers/simple-web-worker/\" class=\"external\" target=\"_blank\">run dedicated worker</a>): This allows you to enter two numbers to be multiplied together. The numbers are sent to a dedicated worker, multiplied together, and the result is returned to the page and displayed.</p>\n<p>This example is rather trivial, but we decided to keep it simple while introducing you to basic worker concepts. More advanced details are covered later on in the article.</p>"}},{"type":"prose","value":{"id":"worker_feature_detection","title":"Worker feature detection","isH3":true,"content":"<p>For slightly more controlled error handling and backwards compatibility, it is a good idea to wrap your worker accessing code in the following (<a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/main.js\" class=\"external\" target=\"_blank\">main.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>if (window.Worker) {\n // …\n}\n</code></pre></div>"}},{"type":"prose","value":{"id":"spawning_a_dedicated_worker","title":"Spawning a dedicated worker","isH3":true,"content":"<p>Creating a new worker is simple. All you need to do is call the <a href=\"/en-US/docs/Web/API/Worker/Worker\" title=\"Worker()\"><code>Worker()</code></a> constructor, specifying the URI of a script to execute in the worker thread (<a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/main.js\" class=\"external\" target=\"_blank\">main.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const myWorker = new Worker(\"worker.js\");\n</code></pre></div>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> Bundlers, including <a href=\"https://webpack.js.org/guides/web-workers/\" class=\"external\" target=\"_blank\">webpack</a>, <a href=\"https://vite.dev/guide/features.html#web-workers\" class=\"external\" target=\"_blank\">Vite</a>, and <a href=\"https://parceljs.org/languages/javascript/#web-workers\" class=\"external\" target=\"_blank\">Parcel</a>, recommend passing URLs that are resolved relative to <a href=\"/en-US/docs/Web/JavaScript/Reference/Operators/import.meta#url\"><code>import.meta.url</code></a> to the <code>Worker()</code> constructor. For example:</p>\n <div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const myWorker = new Worker(new URL(\"worker.js\", import.meta.url));\n</code></pre></div>\n <p>This way, the path is relative to the current script instead of the current HTML page, which allows the bundler to safely do optimizations like renaming (because otherwise the <code>worker.js</code> URL may point to a file not controlled by the bundler, so it cannot make any assumptions).</p>\n</div>"}},{"type":"prose","value":{"id":"sending_messages_to_and_from_a_dedicated_worker","title":"Sending messages to and from a dedicated worker","isH3":true,"content":"<p>The magic of workers happens via the <a href=\"/en-US/docs/Web/API/Worker/postMessage\" title=\"postMessage()\"><code>postMessage()</code></a> method and the <a href=\"/en-US/docs/Web/API/Worker/message_event\" title=\"onmessage\"><code>onmessage</code></a> event handler. When you want to send a message to the worker, you post messages to it like this (<a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/main.js\" class=\"external\" target=\"_blank\">main.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>first.onchange = () => {\n myWorker.postMessage([first.value, second.value]);\n console.log(\"Message posted to worker\");\n};\n\nsecond.onchange = () => {\n myWorker.postMessage([first.value, second.value]);\n console.log(\"Message posted to worker\");\n};\n</code></pre></div>\n<p>So here we have two <a href=\"/en-US/docs/Web/HTML/Element/input\"><code><input></code></a> elements represented by the variables <code>first</code> and <code>second</code>; when the value of either is changed, <code>myWorker.postMessage([first.value,second.value])</code> is used to send the value inside both to the worker, as an array. You can send pretty much anything you like in the message.</p>\n<p>In the worker, we can respond when the message is received by writing an event handler block like this (<a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-web-worker/worker.js\" class=\"external\" target=\"_blank\">worker.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>onmessage = (e) => {\n console.log(\"Message received from main script\");\n const workerResult = `Result: ${e.data[0] * e.data[1]}`;\n console.log(\"Posting message back to main script\");\n postMessage(workerResult);\n};\n</code></pre></div>\n<p>The <code>onmessage</code> handler allows us to run some code whenever a message is received, with the message itself being available in the <code>message</code> event's <code>data</code> attribute. Here we multiply together the two numbers then use <code>postMessage()</code> again, to post the result back to the main thread.</p>\n<p>Back in the main thread, we use <code>onmessage</code> again, to respond to the message sent back from the worker:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>myWorker.onmessage = (e) => {\n result.textContent = e.data;\n console.log(\"Message received from worker\");\n};\n</code></pre></div>\n<p>Here we grab the message event data and set it as the <code>textContent</code> of the result paragraph, so the user can see the result of the calculation.</p>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> Notice that <code>onmessage</code> and <code>postMessage()</code> need to be hung off the <code>Worker</code> object when used in the main script thread, but not when used in the worker. This is because, inside the worker, the worker is effectively the global scope.</p>\n</div>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> When a message is passed between the main thread and worker, it is copied or \"transferred\" (moved), not shared. Read <a href=\"#transferring_data_to_and_from_workers_further_details\">Transferring data to and from workers: further details</a> for a much more thorough explanation.</p>\n</div>"}},{"type":"prose","value":{"id":"terminating_a_worker","title":"Terminating a worker","isH3":true,"content":"<p>If you need to immediately terminate a running worker from the main thread, you can do so by calling the worker's <a href=\"/en-US/docs/Web/API/Worker\" title=\"terminate\"><code>terminate</code></a> method:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>myWorker.terminate();\n</code></pre></div>\n<p>The worker thread is killed immediately.</p>"}},{"type":"prose","value":{"id":"handling_errors","title":"Handling errors","isH3":true,"content":"<p>When a runtime error occurs in the worker, its <code>onerror</code> event handler is called. It receives an event named <code>error</code> which implements the <code>ErrorEvent</code> interface.</p>\n<p>The event doesn't bubble and is cancelable; to prevent the default action from taking place, the worker can call the error event's <a href=\"/en-US/docs/Web/API/Event/preventDefault\"><code>preventDefault()</code></a> method.</p>\n<p>The error event has the following three fields that are of interest:</p>\n<dl>\n <dt id=\"message\"><a href=\"#message\"><code>message</code></a></dt>\n <dd>\n <p>A human-readable error message.</p>\n </dd>\n <dt id=\"filename\"><a href=\"#filename\"><code>filename</code></a></dt>\n <dd>\n <p>The name of the script file in which the error occurred.</p>\n </dd>\n <dt id=\"lineno\"><a href=\"#lineno\"><code>lineno</code></a></dt>\n <dd>\n <p>The line number of the script file on which the error occurred.</p>\n </dd>\n</dl>"}},{"type":"prose","value":{"id":"spawning_subworkers","title":"Spawning subworkers","isH3":true,"content":"<p>Workers may spawn more workers if they wish. So-called sub-workers must be hosted within the same origin as the parent page. Also, the URIs for subworkers are resolved relative to the parent worker's location rather than that of the owning page. This makes it easier for workers to keep track of where their dependencies are.</p>"}},{"type":"prose","value":{"id":"importing_scripts_and_libraries","title":"Importing scripts and libraries","isH3":true,"content":"<p>Worker threads have access to a global function, <code>importScripts()</code>, which lets them import scripts. It accepts zero or more URIs as parameters to resources to import; all the following examples are valid:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>importScripts(); /* imports nothing */\nimportScripts(\"foo.js\"); /* imports just \"foo.js\" */\nimportScripts(\"foo.js\", \"bar.js\"); /* imports two scripts */\nimportScripts(\n \"//example.com/hello.js\",\n); /* You can import scripts from other origins */\n</code></pre></div>\n<p>The browser loads each listed script and executes it. Any global objects from each script may then be used by the worker. If the script can't be loaded, <code>NETWORK_ERROR</code> is thrown, and subsequent code will not be executed. Previously executed code (including code deferred using <a href=\"/en-US/docs/Web/API/WorkerGlobalScope/setTimeout\" title=\"setTimeout()\"><code>setTimeout()</code></a>) will still be functional though. Function declarations <strong>after</strong> the <code>importScripts()</code> method are also kept, since these are always evaluated before the rest of the code.</p>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> Scripts may be downloaded in any order, but will be executed in the order in which you pass the filenames into <code>importScripts()</code>. This is done synchronously; <code>importScripts()</code> does not return until all the scripts have been loaded and executed.</p>\n</div>"}},{"type":"prose","value":{"id":"shared_workers","title":"Shared workers","isH3":false,"content":"<p>A shared worker is accessible by multiple scripts — even if they are being accessed by different windows, iframes or even workers. In this section we'll discuss the JavaScript found in our <a href=\"https://github.com/mdn/dom-examples/tree/main/web-workers/simple-shared-worker\" class=\"external\" target=\"_blank\">Basic shared worker example</a> (<a href=\"https://mdn.github.io/dom-examples/web-workers/simple-shared-worker/\" class=\"external\" target=\"_blank\">run shared worker</a>): This is very similar to the basic dedicated worker example, except that it has two functions available handled by different script files: <em>multiplying two numbers</em>, or <em>squaring a number</em>. Both scripts use the same worker to do the actual calculation required.</p>\n<p>Here we'll concentrate on the differences between dedicated and shared workers. Note that in this example we have two HTML pages, each with JavaScript applied that uses the same single worker file.</p>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> If SharedWorker can be accessed from several browsing contexts, all those browsing contexts must share the exact same origin (same protocol, host, and port).</p>\n</div>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> In Firefox, shared workers cannot be shared between documents loaded in private and non-private windows (<a href=\"https://bugzil.la/1177621\" class=\"external\" target=\"_blank\">Firefox bug 1177621</a>).</p>\n</div>"}},{"type":"prose","value":{"id":"spawning_a_shared_worker","title":"Spawning a shared worker","isH3":true,"content":"<p>Spawning a new shared worker is pretty much the same as with a dedicated worker, but with a different constructor name (see <a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/index.html\" class=\"external\" target=\"_blank\">index.html</a> and <a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/index2.html\" class=\"external\" target=\"_blank\">index2.html</a>) — each one has to spin up the worker using code like the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const myWorker = new SharedWorker(\"worker.js\");\n</code></pre></div>\n<p>One big difference is that with a shared worker you have to communicate via a <code>port</code> object — an explicit port is opened that the scripts can use to communicate with the worker (this is done implicitly in the case of dedicated workers).</p>\n<p>The port connection needs to be started either implicitly by use of the <code>onmessage</code> event handler or explicitly with the <code>start()</code> method before any messages can be posted. Calling <code>start()</code> is only needed if the <code>message</code> event is wired up via the <code>addEventListener()</code> method.</p>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> When using the <code>start()</code> method to open the port connection, it needs to be called from both the parent thread and the worker thread if two-way communication is needed.</p>\n</div>"}},{"type":"prose","value":{"id":"sending_messages_to_and_from_a_shared_worker","title":"Sending messages to and from a shared worker","isH3":true,"content":"<p>Now messages can be sent to the worker as before, but the <code>postMessage()</code> method has to be invoked through the port object (again, you'll see similar constructs in both <a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/multiply.js\" class=\"external\" target=\"_blank\">multiply.js</a> and <a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/square.js\" class=\"external\" target=\"_blank\">square.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>squareNumber.onchange = () => {\n myWorker.port.postMessage([squareNumber.value, squareNumber.value]);\n console.log(\"Message posted to worker\");\n};\n</code></pre></div>\n<p>Now, on to the worker. There is a bit more complexity here as well (<a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/worker.js\" class=\"external\" target=\"_blank\">worker.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>onconnect = (e) => {\n const port = e.ports[0];\n\n port.onmessage = (e) => {\n const workerResult = `Result: ${e.data[0] * e.data[1]}`;\n port.postMessage(workerResult);\n };\n};\n</code></pre></div>\n<p>First, we use an <code>onconnect</code> handler to fire code when a connection to the port happens (i.e. when the <code>onmessage</code> event handler in the parent thread is set up, or when the <code>start()</code> method is explicitly called in the parent thread).</p>\n<p>We use the <code>ports</code> attribute of this event object to grab the port and store it in a variable.</p>\n<p>Next, we add an <code>onmessage</code> handler on the port to do the calculation and return the result to the main thread. Setting up this <code>onmessage</code> handler in the worker thread also implicitly opens the port connection back to the parent thread, so the call to <code>port.start()</code> is not actually needed, as noted above.</p>\n<p>Finally, back in the main script, we deal with the message (again, you'll see similar constructs in both <a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/multiply.js\" class=\"external\" target=\"_blank\">multiply.js</a> and <a href=\"https://github.com/mdn/dom-examples/blob/main/web-workers/simple-shared-worker/square.js\" class=\"external\" target=\"_blank\">square.js</a>):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>myWorker.port.onmessage = (e) => {\n result2.textContent = e.data;\n console.log(\"Message received from worker\");\n};\n</code></pre></div>\n<p>When a message comes back through the port from the worker, we insert the calculation result inside the appropriate result paragraph.</p>"}},{"type":"prose","value":{"id":"about_thread_safety","title":"About thread safety","isH3":false,"content":"<p>The <a href=\"/en-US/docs/Web/API/Worker\"><code>Worker</code></a> interface spawns real OS-level threads, and mindful programmers may be concerned that concurrency can cause \"interesting\" effects in your code if you aren't careful.</p>\n<p>However, since web workers have carefully controlled communication points with other threads, it's actually very hard to cause concurrency problems. There's no access to non-threadsafe components or the DOM. And you have to pass specific data in and out of a thread through serialized objects. So you have to work really hard to cause problems in your code.</p>"}},{"type":"prose","value":{"id":"content_security_policy","title":"Content security policy","isH3":false,"content":"<p>Workers are considered to have their own execution context, distinct from the document that created them. For this reason they are, in general, not governed by the <a href=\"/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy\">content security policy</a> of the document (or parent worker) that created them. So for example, suppose a document is served with the following header:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">http</span></div><pre class=\"brush: http notranslate\"><code>Content-Security-Policy: script-src 'self'\n</code></pre></div>\n<p>Among other things, this will prevent any scripts it includes from using <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval\"><code>eval()</code></a>. However, if the script constructs a worker, code running in the worker's context <em>will</em> be allowed to use <code>eval()</code>.</p>\n<p>To specify a content security policy for the worker, set a <a href=\"/en-US/docs/Web/HTTP/Headers/Content-Security-Policy\">Content-Security-Policy</a> response header for the request which delivered the worker script itself.</p>\n<p>The exception to this is if the worker script's origin is a globally unique identifier (for example, if its URL has a scheme of data or blob). In this case, the worker does inherit the CSP of the document or worker that created it.</p>"}},{"type":"prose","value":{"id":"transferring_data_to_and_from_workers_further_details","title":"Transferring data to and from workers: further details","isH3":false,"content":"<p>Data passed between the main page and workers is <strong>copied</strong>, not shared. Objects are serialized as they're handed to the worker, and subsequently, de-serialized on the other end. The page and worker <strong>do not share the same instance</strong>, so the end result is that <strong>a duplicate</strong> is created on each end. Most browsers implement this feature as <a href=\"/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm\">structured cloning</a>.</p>\n<p>To illustrate this, let's create a function named <code>emulateMessage()</code>, which will simulate the behavior of a value that is <em>cloned and not shared</em> during the passage from a <code>worker</code> to the main page or vice versa:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>function emulateMessage(vVal) {\n return eval(`(${JSON.stringify(vVal)})`);\n}\n\n// Tests\n\n// test #1\nconst example1 = new Number(3);\nconsole.log(typeof example1); // object\nconsole.log(typeof emulateMessage(example1)); // number\n\n// test #2\nconst example2 = true;\nconsole.log(typeof example2); // boolean\nconsole.log(typeof emulateMessage(example2)); // boolean\n\n// test #3\nconst example3 = new String(\"Hello World\");\nconsole.log(typeof example3); // object\nconsole.log(typeof emulateMessage(example3)); // string\n\n// test #4\nconst example4 = {\n name: \"Carina Anand\",\n age: 43,\n};\nconsole.log(typeof example4); // object\nconsole.log(typeof emulateMessage(example4)); // object\n\n// test #5\nfunction Animal(type, age) {\n this.type = type;\n this.age = age;\n}\nconst example5 = new Animal(\"Cat\", 3);\nalert(example5.constructor); // Animal\nalert(emulateMessage(example5).constructor); // Object\n</code></pre></div>\n<p>A value that is cloned and not shared is called <em>message</em>. As you will probably know by now, <em>messages</em> can be sent to and from the main thread by using <code>postMessage()</code>, and the <code>message</code> event's <a href=\"/en-US/docs/Web/API/MessageEvent/data\" title=\"data\"><code>data</code></a> attribute contains data passed back from the worker.</p>\n<p><strong>example.html</strong>: (the main page):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const myWorker = new Worker(\"my_task.js\");\n\nmyWorker.onmessage = (event) => {\n console.log(`Worker said : ${event.data}`);\n};\n\nmyWorker.postMessage(\"ali\");\n</code></pre></div>\n<p><strong>my_task.js</strong> (the worker):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>postMessage(\"I'm working before postMessage('ali').\");\n\nonmessage = (event) => {\n postMessage(`Hi, ${event.data}`);\n};\n</code></pre></div>\n<p>The <a href=\"/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm\">structured cloning</a> algorithm can accept JSON and a few things that JSON can't — like circular references.</p>"}},{"type":"prose","value":{"id":"passing_data_examples","title":"Passing data examples","isH3":true,"content":"<h4 id=\"example_1_advanced_passing_json_data_and_creating_a_switching_system\">Example 1: Advanced passing JSON Data and creating a switching system</h4>\n<p>If you have to pass some complex data and have to call many different functions both on the main page and in the Worker, you can create a system which groups everything together.</p>\n<p>First, we create a <code>QueryableWorker</code> class that takes the URL of the worker, a default listener, and an error handler, and this class is going to keep track of a list of listeners and help us communicate with the worker:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>function QueryableWorker(url, defaultListener, onError) {\n const instance = this;\n const worker = new Worker(url);\n const listeners = {};\n\n this.defaultListener = defaultListener ?? (() => {});\n\n if (onError) {\n worker.onerror = onError;\n }\n\n this.postMessage = (message) => {\n worker.postMessage(message);\n };\n\n this.terminate = () => {\n worker.terminate();\n };\n}\n</code></pre></div>\n<p>Then we add the methods of adding/removing listeners:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>this.addListeners = (name, listener) => {\n listeners[name] = listener;\n};\n\nthis.removeListeners = (name) => {\n delete listeners[name];\n};\n</code></pre></div>\n<p>Here we let the worker handle two simple operations for illustration: getting the difference of two numbers and making an alert after three seconds. In order to achieve that we first implement a <code>sendQuery</code> method which queries if the worker actually has the corresponding methods to do what we want.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// This functions takes at least one argument, the method name we want to query.\n// Then we can pass in the arguments that the method needs.\nthis.sendQuery = (queryMethod, ...queryMethodArguments) => {\n if (!queryMethod) {\n throw new TypeError(\n \"QueryableWorker.sendQuery takes at least one argument\",\n );\n }\n worker.postMessage({\n queryMethod,\n queryMethodArguments,\n });\n};\n</code></pre></div>\n<p>We finish QueryableWorker with the <code>onmessage</code> method. If the worker has the corresponding methods we queried, it should return the name of the corresponding listener and the arguments it needs, we just need to find it in <code>listeners</code>.:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>worker.onmessage = (event) => {\n if (\n event.data instanceof Object &&\n Object.hasOwn(event.data, \"queryMethodListener\") &&\n Object.hasOwn(event.data, \"queryMethodArguments\")\n ) {\n listeners[event.data.queryMethodListener].apply(\n instance,\n event.data.queryMethodArguments,\n );\n } else {\n this.defaultListener.call(instance, event.data);\n }\n};\n</code></pre></div>\n<p>Now onto the worker. First we need to have the methods to handle the two simple operations:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const queryableFunctions = {\n getDifference(a, b) {\n reply(\"printStuff\", a - b);\n },\n waitSomeTime() {\n setTimeout(() => {\n reply(\"doAlert\", 3, \"seconds\");\n }, 3000);\n },\n};\n\nfunction reply(queryMethodListener, ...queryMethodArguments) {\n if (!queryMethodListener) {\n throw new TypeError(\"reply - takes at least one argument\");\n }\n postMessage({\n queryMethodListener,\n queryMethodArguments,\n });\n}\n\n/* This method is called when main page calls QueryWorker's postMessage method directly*/\nfunction defaultReply(message) {\n // do something\n}\n</code></pre></div>\n<p>And the <code>onmessage</code> method is now trivial:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>onmessage = (event) => {\n if (\n event.data instanceof Object &&\n Object.hasOwn(event.data, \"queryMethod\") &&\n Object.hasOwn(event.data, \"queryMethodArguments\")\n ) {\n queryableFunctions[event.data.queryMethod].apply(\n self,\n event.data.queryMethodArguments,\n );\n } else {\n defaultReply(event.data);\n }\n};\n</code></pre></div>\n<p>Here are the full implementation:</p>\n<p><strong>example.html</strong> (the main page):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">html</span></div><pre class=\"brush: html notranslate\"><code><!doctype html>\n<html lang=\"en-US\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width\" />\n <title>MDN Example - Queryable worker</title>\n <script type=\"text/javascript\">\n // QueryableWorker instances methods:\n // * sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc.): calls a Worker's queryable function\n // * postMessage(string or JSON Data): see Worker.prototype.postMessage()\n // * terminate(): terminates the Worker\n // * addListener(name, function): adds a listener\n // * removeListener(name): removes a listener\n // QueryableWorker instances properties:\n // * defaultListener: the default listener executed only when the Worker calls the postMessage() function directly\n function QueryableWorker(url, defaultListener, onError) {\n const instance = this;\n const worker = new Worker(url);\n const listeners = {};\n\n this.defaultListener = defaultListener ?? (() => {});\n\n if (onError) {\n worker.onerror = onError;\n }\n\n this.postMessage = (message) => {\n worker.postMessage(message);\n };\n\n this.terminate = () => {\n worker.terminate();\n };\n\n this.addListener = (name, listener) => {\n listeners[name] = listener;\n };\n\n this.removeListener = (name) => {\n delete listeners[name];\n };\n\n // This functions takes at least one argument, the method name we want to query.\n // Then we can pass in the arguments that the method needs.\n this.sendQuery = (queryMethod, ...queryMethodArguments) => {\n if (!queryMethod) {\n throw new TypeError(\n \"QueryableWorker.sendQuery takes at least one argument\",\n );\n }\n worker.postMessage({\n queryMethod,\n queryMethodArguments,\n });\n };\n\n worker.onmessage = (event) => {\n if (\n event.data instanceof Object &&\n Object.hasOwn(event.data, \"queryMethodListener\") &&\n Object.hasOwn(event.data, \"queryMethodArguments\")\n ) {\n listeners[event.data.queryMethodListener].apply(\n instance,\n event.data.queryMethodArguments,\n );\n } else {\n this.defaultListener.call(instance, event.data);\n }\n };\n }\n\n // your custom \"queryable\" worker\n const myTask = new QueryableWorker(\"my_task.js\");\n\n // your custom \"listeners\"\n myTask.addListener(\"printStuff\", (result) => {\n document\n .getElementById(\"firstLink\")\n .parentNode.appendChild(\n document.createTextNode(`The difference is ${result}!`),\n );\n });\n\n myTask.addListener(\"doAlert\", (time, unit) => {\n alert(`Worker waited for ${time} ${unit} :-)`);\n });\n </script>\n </head>\n <body>\n <ul>\n <li>\n <a\n id=\"firstLink\"\n href=\"javascript:myTask.sendQuery('getDifference', 5, 3);\"\n >What is the difference between 5 and 3?</a\n >\n </li>\n <li>\n <a href=\"javascript:myTask.sendQuery('waitSomeTime');\"\n >Wait 3 seconds</a\n >\n </li>\n <li>\n <a href=\"javascript:myTask.terminate();\">terminate() the Worker</a>\n </li>\n </ul>\n </body>\n</html>\n</code></pre></div>\n<p><strong>my_task.js</strong> (the worker):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const queryableFunctions = {\n // example #1: get the difference between two numbers:\n getDifference(minuend, subtrahend) {\n reply(\"printStuff\", minuend - subtrahend);\n },\n\n // example #2: wait three seconds\n waitSomeTime() {\n setTimeout(() => {\n reply(\"doAlert\", 3, \"seconds\");\n }, 3000);\n },\n};\n\n// system functions\n\nfunction defaultReply(message) {\n // your default PUBLIC function executed only when main page calls the queryableWorker.postMessage() method directly\n // do something\n}\n\nfunction reply(queryMethodListener, ...queryMethodArguments) {\n if (!queryMethodListener) {\n throw new TypeError(\"reply - not enough arguments\");\n }\n postMessage({\n queryMethodListener,\n queryMethodArguments,\n });\n}\n\nonmessage = (event) => {\n if (\n event.data instanceof Object &&\n Object.hasOwn(event.data, \"queryMethod\") &&\n Object.hasOwn(event.data, \"queryMethodArguments\")\n ) {\n queryableFunctions[event.data.queryMethod].apply(\n self,\n event.data.queryMethodArguments,\n );\n } else {\n defaultReply(event.data);\n }\n};\n</code></pre></div>\n<p>It is possible to switch the content of each mainpage -> worker and worker -> mainpage message. And the property names \"queryMethod\", \"queryMethodListeners\", \"queryMethodArguments\" can be anything as long as they are consistent in <code>QueryableWorker</code> and the <code>worker</code>.</p>"}},{"type":"prose","value":{"id":"passing_data_by_transferring_ownership_transferable_objects","title":"Passing data by transferring ownership (transferable objects)","isH3":true,"content":"<p>Modern browsers contain an additional way to pass certain types of objects to or from a worker with high performance. <a href=\"/en-US/docs/Web/API/Web_Workers_API/Transferable_objects\">Transferable objects</a> are transferred from one context to another with a zero-copy operation, which results in a vast performance improvement when sending large data sets.</p>\n<p>For example, when transferring an <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer\"><code>ArrayBuffer</code></a> from your main app to a worker script, the original <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer\"><code>ArrayBuffer</code></a> is cleared and no longer usable. Its content is (quite literally) transferred to the worker context.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Create a 32MB \"file\" and fill it with consecutive values from 0 to 255 – 32MB = 1024 * 1024 * 32\nconst uInt8Array = new Uint8Array(1024 * 1024 * 32).map((v, i) => i);\nworker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);\n</code></pre></div>"}},{"type":"prose","value":{"id":"embedded_workers","title":"Embedded workers","isH3":false,"content":"<p>There is not an \"official\" way to embed the code of a worker within a web page, like <a href=\"/en-US/docs/Web/HTML/Element/script\"><code><script></code></a> elements do for normal scripts. But a <a href=\"/en-US/docs/Web/HTML/Element/script\"><code><script></code></a> element that does not have a <code>src</code> attribute and has a <code>type</code> attribute that does not identify an executable MIME type can be considered a data block element that JavaScript could use. \"Data blocks\" is a more general feature of HTML that can carry almost any textual data. So, a worker could be embedded in this way:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">html</span></div><pre class=\"brush: html notranslate\"><code><!doctype html>\n<html lang=\"en-US\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width\" />\n <title>MDN Example - Embedded worker</title>\n <script type=\"text/js-worker\">\n // This script WON'T be parsed by JS engines because its MIME type is text/js-worker.\n const myVar = 'Hello World!';\n // Rest of your worker code goes here.\n </script>\n <script>\n // This script WILL be parsed by JS engines because its MIME type is text/javascript.\n function pageLog(sMsg) {\n // Use a fragment: browser will only render/reflow once.\n const frag = document.createDocumentFragment();\n frag.appendChild(document.createTextNode(sMsg));\n frag.appendChild(document.createElement(\"br\"));\n document.querySelector(\"#logDisplay\").appendChild(frag);\n }\n </script>\n <script type=\"text/js-worker\">\n // This script WON'T be parsed by JS engines because its MIME type is text/js-worker.\n onmessage = (event) => {\n postMessage(myVar);\n };\n // Rest of your worker code goes here.\n </script>\n <script>\n // This script WILL be parsed by JS engines because its MIME type is text/javascript.\n\n // In the past blob builder existed, but now we use Blob\n const blob = new Blob(\n Array.prototype.map.call(\n document.querySelectorAll(\"script[type='text\\/js-worker']\"),\n (script) => script.textContent,\n ),\n { type: \"text/javascript\" },\n );\n\n // Creating a new document.worker property containing all our \"text/js-worker\" scripts.\n document.worker = new Worker(window.URL.createObjectURL(blob));\n\n document.worker.onmessage = (event) => {\n pageLog(`Received: ${event.data}`);\n };\n\n // Start the worker.\n window.onload = () => {\n document.worker.postMessage(\"\");\n };\n </script>\n </head>\n <body>\n <div id=\"logDisplay\"></div>\n </body>\n</html>\n</code></pre></div>\n<p>The embedded worker is now nested into a new custom <code>document.worker</code> property.</p>\n<p>It is also worth noting that you can also convert a function into a Blob, then generate an object URL from that blob. For example:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>function fn2workerURL(fn) {\n const blob = new Blob([`(${fn.toString()})()`], { type: \"text/javascript\" });\n return URL.createObjectURL(blob);\n}\n</code></pre></div>"}},{"type":"prose","value":{"id":"further_examples","title":"Further examples","isH3":false,"content":"<p>This section provides further examples of how to use web workers.</p>"}},{"type":"prose","value":{"id":"performing_computations_in_the_background","title":"Performing computations in the background","isH3":true,"content":"<p>Workers are mainly useful for allowing your code to perform processor-intensive calculations without blocking the user interface thread. In this example, a worker is used to calculate Fibonacci numbers.</p>\n<h4 id=\"the_javascript_code\">The JavaScript code</h4>\n<p>The following JavaScript code is stored in the \"fibonacci.js\" file referenced by the HTML in the next section.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>self.onmessage = (event) => {\n const userNum = Number(event.data);\n self.postMessage(fibonacci(userNum));\n};\n\nfunction fibonacci(num) {\n let a = 1;\n let b = 0;\n while (num > 0) {\n [a, b] = [a + b, a];\n num--;\n }\n\n return b;\n}\n</code></pre></div>\n<p>The worker sets the property <code>onmessage</code> to a function which will receive messages sent when the worker object's <code>postMessage()</code> is called. This performs the math and eventually returns the result back to the main thread.</p>\n<h4 id=\"the_html_code\">The HTML code</h4>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">html</span></div><pre class=\"brush: html notranslate\"><code><!doctype html>\n<html lang=\"en-US\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>Fibonacci number generator</title>\n <style>\n body {\n width: 500px;\n }\n\n div,\n p {\n margin-bottom: 20px;\n }\n </style>\n </head>\n <body>\n <form>\n <div>\n <label for=\"number\"\n >Enter a number that is a zero-based index position in the fibonacci\n sequence to see what number is in that position. For example, enter 6\n and you'll get a result of 8 — the fibonacci number at index position\n 6 is 8.</label\n >\n <input type=\"number\" id=\"number\" />\n </div>\n <div>\n <input type=\"submit\" />\n </div>\n </form>\n\n <p id=\"result\"></p>\n\n <script>\n const form = document.querySelector(\"form\");\n const input = document.querySelector('input[type=\"number\"]');\n const result = document.querySelector(\"p#result\");\n const worker = new Worker(\"fibonacci.js\");\n\n worker.onmessage = (event) => {\n result.textContent = event.data;\n console.log(`Got: ${event.data}`);\n };\n\n worker.onerror = (error) => {\n console.log(`Worker error: ${error.message}`);\n throw error;\n };\n\n form.onsubmit = (e) => {\n e.preventDefault();\n worker.postMessage(input.value);\n input.value = \"\";\n };\n </script>\n </body>\n</html>\n</code></pre></div>\n<p>The web page creates a <code><p></code> element with the ID <code>result</code>, which gets used to display the result, then spawns the worker. After spawning the worker, the <code>onmessage</code> handler is configured to display the results by setting the contents of the <code><p></code> element, and the <code>onerror</code> handler is set to log the error message to the devtools console.</p>\n<p>Finally, a message is sent to the worker to start it.</p>\n<p><a href=\"https://mdn.github.io/dom-examples/web-workers/fibonacci-worker/\" class=\"external\" target=\"_blank\">Try this example live</a>.</p>"}},{"type":"prose","value":{"id":"dividing_tasks_among_multiple_workers","title":"Dividing tasks among multiple workers","isH3":true,"content":"<p>As multicore computers become increasingly common, it's often useful to divide computationally complex tasks among multiple workers, which may then perform those tasks on multiple-processor cores.</p>"}},{"type":"prose","value":{"id":"other_types_of_workers","title":"Other types of workers","isH3":false,"content":"<p>In addition to dedicated and shared web workers, there are other types of workers available:</p>\n<ul>\n <li><a href=\"/en-US/docs/Web/API/Service_Worker_API\">ServiceWorkers</a> essentially act as proxy servers that sit between web applications, and the browser and network (when available). They are intended to (amongst other things) enable the creation of effective offline experiences, intercepting network requests and taking appropriate action based on whether the network is available and updated assets reside on the server. They will also allow access to push notifications and background sync APIs.</li>\n <li><a href=\"/en-US/docs/Web/API/Web_Audio_API#audio_processing_in_javascript\">Audio Worklet</a> provide the ability for direct scripted audio processing to be done in a worklet (a lightweight version of worker) context.</li>\n</ul>"}},{"type":"prose","value":{"id":"debugging_worker_threads","title":"Debugging worker threads","isH3":false,"content":"<p>Most browsers enable you to debug web workers in their JavaScript debuggers in <em>exactly the same way</em> as debugging the main thread! For example, both Firefox and Chrome list JavaScript source files for both the main thread and active worker threads, and all of these files can be opened to set breakpoints and logpoints.</p>\n<p>To learn how to debug web workers, see the documentation for each browser's JavaScript debugger:</p>\n<ul>\n <li><a href=\"https://developer.chrome.com/docs/devtools/sources\" class=\"external\" target=\"_blank\">Chrome Sources panel</a></li>\n <li><a href=\"https://firefox-source-docs.mozilla.org/devtools-user/debugger/\" class=\"external\" target=\"_blank\">Firefox JavaScript Debugger</a></li>\n</ul>"}},{"type":"prose","value":{"id":"functions_and_interfaces_available_in_workers","title":"Functions and interfaces available in workers","isH3":false,"content":"<p>You can use most standard JavaScript features inside a web worker, including:</p>\n<ul>\n <li><a href=\"/en-US/docs/Web/API/Navigator\"><code>Navigator</code></a></li>\n <li><a href=\"/en-US/docs/Web/API/WorkerGlobalScope/fetch\" title=\"fetch()\"><code>fetch()</code></a></li>\n <li><a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\"><code>Array</code></a>, <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date\"><code>Date</code></a>, <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math\"><code>Math</code></a>, and <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/String\"><code>String</code></a></li>\n <li><a href=\"/en-US/docs/Web/API/WorkerGlobalScope/setTimeout\" title=\"setTimeout()\"><code>setTimeout()</code></a> and <a href=\"/en-US/docs/Web/API/WorkerGlobalScope/setInterval\" title=\"setInterval()\"><code>setInterval()</code></a></li>\n</ul>\n<p>The main thing you <em>can't</em> do in a Worker is directly affect the parent page. This includes manipulating the DOM and using that page's objects. You have to do it indirectly, by sending a message back to the main script via <a href=\"/en-US/docs/Web/API/DedicatedWorkerGlobalScope/postMessage\"><code>DedicatedWorkerGlobalScope.postMessage()</code></a>, then doing the changes in event handler.</p>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> You can test whether a method is available to workers using the site: <a href=\"https://worker-playground.glitch.me/\" class=\"external\" target=\"_blank\">https://worker-playground.glitch.me/</a>. For example, if you enter <a href=\"/en-US/docs/Web/API/EventSource\"><code>EventSource</code></a> into the site on Firefox 84 you'll see that this is not supported in service workers, but is in dedicated and shared workers.</p>\n</div>\n<div class=\"notecard note\">\n <p><strong>Note:</strong> For a complete list of functions available to workers, see <a href=\"/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers\">Functions and interfaces available to workers</a>.</p>\n</div>"}},{"type":"specifications","value":{"title":"Specifications","id":"specifications","isH3":false,"specifications":[{"bcdSpecificationURL":"https://html.spec.whatwg.org/multipage/#workers","title":"HTML Standard"}],"query":"undefined"}},{"type":"prose","value":{"id":"see_also","title":"See also","isH3":false,"content":"<ul>\n <li><a href=\"/en-US/docs/Web/API/Worker\"><code>Worker</code></a> interface</li>\n <li><a href=\"/en-US/docs/Web/API/SharedWorker\"><code>SharedWorker</code></a> interface</li>\n <li><a href=\"/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers\">Functions available to workers</a></li>\n <li><a href=\"/en-US/docs/Web/API/OffscreenCanvas\"><code>OffscreenCanvas</code></a> interface</li>\n</ul>"}}],"toc":[{"text":"Web Workers API","id":"web_workers_api"},{"text":"Dedicated workers","id":"dedicated_workers"},{"text":"Shared workers","id":"shared_workers"},{"text":"About thread safety","id":"about_thread_safety"},{"text":"Content security policy","id":"content_security_policy"},{"text":"Transferring data to and from workers: further details","id":"transferring_data_to_and_from_workers_further_details"},{"text":"Embedded workers","id":"embedded_workers"},{"text":"Further examples","id":"further_examples"},{"text":"Other types of workers","id":"other_types_of_workers"},{"text":"Debugging worker threads","id":"debugging_worker_threads"},{"text":"Functions and interfaces available in workers","id":"functions_and_interfaces_available_in_workers"},{"text":"Specifications","id":"specifications"},{"text":"See also","id":"see_also"}],"summary":"Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can make network requests using the fetch() or XMLHttpRequest APIs. Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa).","popularity":0.2505,"modified":"2024-11-22T16:43:48.000Z","other_translations":[{"locale":"de","title":"Verwendung von Web Workern","native":"Deutsch"},{"locale":"es","title":"Usando Web Workers","native":"Español"},{"locale":"fr","title":"Utilisation des web workers","native":"Français"},{"locale":"ja","title":"ウェブワーカーの使用","native":"日本語"},{"locale":"ru","title":"Использование Web Workers","native":"Русский"},{"locale":"zh-CN","title":"使用 Web Worker","native":"中文 (简体)"},{"locale":"zh-TW","title":"使用 Web Worker","native":"正體中文 (繁體)"}],"pageType":"guide","source":{"folder":"en-us/web/api/web_workers_api/using_web_workers","github_url":"https://github.com/mdn/content/blob/main/files/en-us/web/api/web_workers_api/using_web_workers/index.md","last_commit_url":"https://github.com/mdn/content/commit/5f76b99045f87349ed030bbd6a3c2e43badb3c22","filename":"index.md"},"short_title":"Using Web Workers","parents":[{"uri":"/en-US/docs/Web","title":"References"},{"uri":"/en-US/docs/Web/API","title":"Web APIs"},{"uri":"/en-US/docs/Web/API/Web_Workers_API","title":"Web Workers API"},{"uri":"/en-US/docs/Web/API/Web_Workers_API/Using_web_workers","title":"Using Web Workers"}],"pageTitle":"Using Web Workers - Web APIs | MDN","noIndexing":false}}</script></body></html>