CINXE.COM
Client-seitiger Speicher - Lernen Sie Webentwicklung | 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>Client-seitiger Speicher - Lernen Sie Webentwicklung | MDN</title><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="en"/><link rel="alternate" title="Almacenamiento del lado cliente" href="https://developer.mozilla.org/es/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="es"/><link rel="alternate" title="Stockage côté client" href="https://developer.mozilla.org/fr/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="fr"/><link rel="alternate" title="クライアント側ストレージ" href="https://developer.mozilla.org/ja/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="ja"/><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/pt-BR/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="pt"/><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/ru/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="ru"/><link rel="alternate" title="客户端存储" href="https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="zh"/><link rel="alternate" title="Client-seitiger Speicher" href="https://developer.mozilla.org/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" hrefLang="de"/><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="Moderne Webbrowser unterstützen eine Vielzahl von Möglichkeiten, wie Websites Daten auf dem Rechner des Nutzers speichern und bei Bedarf abrufen können – mit der Erlaubnis des Nutzers. Dies ermöglicht Ihnen, Daten für die langfristige Speicherung zu speichern, Seiten oder Dokumente für die Offline-Nutzung zu sichern, nutzerspezifische Einstellungen für Ihre Website zu behalten und mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Techniken."/><meta property="og:url" content="https://developer.mozilla.org/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage"/><meta property="og:title" content="Client-seitiger Speicher - Lernen Sie Webentwicklung | MDN"/><meta property="og:type" content="website"/><meta property="og:locale" content="de"/><meta property="og:description" content="Moderne Webbrowser unterstützen eine Vielzahl von Möglichkeiten, wie Websites Daten auf dem Rechner des Nutzers speichern und bei Bedarf abrufen können – mit der Erlaubnis des Nutzers. Dies ermöglicht Ihnen, Daten für die langfristige Speicherung zu speichern, Seiten oder Dokumente für die Offline-Nutzung zu sichern, nutzerspezifische Einstellungen für Ihre Website zu behalten und mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Techniken."/><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/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage"/><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.f565372a.js"></script><link href="/static/css/main.3d9e7a02.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="/de/" 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 "><button type="button" id="references-button" class="top-level-entry menu-toggle" aria-controls="references-menu" aria-expanded="false">References</button><a href="/de/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="/de/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="/de/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="/de/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="/de/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="/de/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="/de/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="/de/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=" "><a href="/de/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">Build web projects usable for all</p></div></a></li><li class="apis-link-container desktop-only "><a href="/de/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 active"><button type="button" id="learn-button" class="top-level-entry menu-toggle" aria-controls="learn-menu" aria-expanded="false">Learn</button><a href="/de/docs/Learn_web_development" class="top-level-entry">Learn</a><ul id="learn-menu" class="submenu learn hidden inline-submenu-lg" aria-labelledby="learn-button"><li class="apis-link-container mobile-only "><a href="/de/docs/Learn_web_development" 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="/de/docs/Learn_web_development" 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="/de/docs/Learn_web_development/Core/Structuring_content" 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="/de/docs/Learn_web_development/Core/Styling_basics" 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="/de/docs/Learn_web_development/Core/Scripting" 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="/de/docs/Learn_web_development/Core/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="/de/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="/de/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="/de/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="/de/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="/de/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="/de/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=%2Fde%2Fdocs%2FLearn_web_development%2FExtensions%2FClient-side_APIs%2FClient-side_storage" class="login-link" rel="nofollow">Log in</a></li><li><a href="/users/fxa/login/authenticate/?next=%2Fde%2Fdocs%2FLearn_web_development%2FExtensions%2FClient-side_APIs%2FClient-side_storage" 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="/de/docs/Learn_web_development" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Lernen Sie Webentwicklung</span></a><meta property="position" content="1"/></li><li property="itemListElement" typeof="ListItem"><a href="/de/docs/Learn_web_development/Extensions" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Erweiterungsmodule</span></a><meta property="position" content="2"/></li><li property="itemListElement" typeof="ListItem"><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Client-seitige Web-APIs</span></a><meta property="position" content="3"/></li><li property="itemListElement" typeof="ListItem"><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="breadcrumb-current-page" property="item" typeof="WebPage"><span property="name">Client-seitiger Speicher</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>Deutsch<span title="Diese Übersetzung ist Teil eines Experiments."><span class="icon icon-experimental "></span></span></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="en-US" href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>English (US)</span></a></li><li class=" "><a data-locale="es" href="/es/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>Español</span></a></li><li class=" "><a data-locale="fr" href="/fr/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>Français</span></a></li><li class=" "><a data-locale="ja" href="/ja/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>日本語</span></a></li><li class=" "><a data-locale="pt-BR" href="/pt-BR/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>Português (do Brasil)</span></a></li><li class=" "><a data-locale="ru" href="/ru/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>Русский</span></a></li><li class=" "><a data-locale="zh-CN" href="/zh-CN/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" class="button submenu-item"><span>中文 (简体)</span></a></li></ul></div></div></li></ul></div></div></div></div><div class="container"><div class="notecard experimental localized-content-note"><p><a href="https://github.com/orgs/mdn/discussions/741" class="external"><strong>Experiment</strong>: Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten.</a></p></div></div><div class="main-wrapper"><div class="sidebar-container"><aside id="sidebar-quicklinks" class="sidebar"><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 diesem Artikel</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#client-seitiger_speicher">Client-seitiger Speicher?</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speichern_einfacher_daten_–_web_storage">Speichern einfacher Daten – Web Storage</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speichern_komplexer_daten_–_indexeddb">Speichern komplexer Daten – IndexedDB</a></li><li class="document-toc-item "><a class="document-toc-link" href="#offline-asset-speicherung">Offline-Asset-Speicherung</a></li><li class="document-toc-item "><a class="document-toc-link" href="#zusammenfassung">Zusammenfassung</a></li><li class="document-toc-item "><a class="document-toc-link" href="#siehe_auch">Siehe auch</a></li></ul></section></div></div><div class="sidebar-body"><ol><li class="section"><a href="/de/docs/Learn_web_development/Getting_started">Einstiegsmodule</a></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Getting_started/Environment_setup">Umgebung einrichten</a></summary><ol><li><a href="/de/docs/Learn_web_development/Getting_started/Environment_setup/Installing_software">Installation grundlegender Software</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web">Surfen im Web</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Environment_setup/Code_editors">Code-Editor</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Environment_setup/Dealing_with_files">Umgang mit Dateien</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Environment_setup/Command_line">Leitfaden für die Befehlszeilen-Einführung</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Getting_started/Your_first_website">Ihre erste Website</a></summary><ol><li><a href="/de/docs/Learn_web_development/Getting_started/Your_first_website/What_will_your_website_look_like">Wie wird Ihre Website aussehen?</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Your_first_website/Creating_the_content">HTML: Erstellen der Inhalte</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Your_first_website/Styling_the_content">CSS: Gestaltung des Inhalts</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Your_first_website/Adding_interactivity">JavaScript: Interaktivität hinzufügen</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Your_first_website/Publishing_your_website">Veröffentlichen Ihrer Website</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Getting_started/Web_standards">Webstandards</a></summary><ol><li><a href="/de/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works">How the web works</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Web_standards/The_web_standards_model">Das Modell der Webstandards</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites">Wie Browser Websites laden</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Getting_started/Soft_skills">Soziale Kompetenzen</a></summary><ol><li><a href="/de/docs/Learn_web_development/Getting_started/Soft_skills/Research_and_learning">Forschung und Lernen</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Soft_skills/Collaboration_and_teamwork">Zusammenarbeit und Teamarbeit</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Soft_skills/Workflows_and_processes">Workflows und Prozesse</a></li><li><a href="/de/docs/Learn_web_development/Getting_started/Soft_skills/Job_interviews">Erfolgreich in Vorstellungsgesprächen</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn_web_development/Core">Kernmodule</a></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/Structuring_content">Inhalte mit HTML strukturieren</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax">Grundlegende HTML-Syntax</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata">Was befindet sich im Kopf? Metadaten einer Webseite</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Headings_and_paragraphs">Überschriften und Absätze in HTML</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Emphasis_and_importance">Hervorhebung und Wichtigkeit</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Lists">Listen</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Structuring_documents">Strukturierung von Dokumenten</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Advanced_text_features">Erweiterte Textfunktionen</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Creating_links">Erstellen von Links</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Marking_up_a_letter">Herausforderung: Eine E-Mail korrekt auszeichnen</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Structuring_a_page_of_content">Herausforderung: Strukturierung einer Inhaltsseite</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/HTML_images">HTML-Bilder</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/HTML_video_and_audio">HTML video und audio</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Mozilla_splash_page">Herausforderung: Mozilla Splash-Seite</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics">Grundlagen von HTML-Tabellen</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Table_accessibility">Barrierefreiheit von HTML-Tabellen</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Planet_data_table">Herausforderung: Strukturierung einer Planeten-Datentabelle</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/HTML_forms">Formulare und Schaltflächen in HTML</a></li><li><a href="/de/docs/Learn_web_development/Core/Structuring_content/Debugging_HTML">Debugging von HTML</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/Styling_basics">Grundlagen des CSS-Stylings</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/What_is_CSS">Was ist CSS?</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Getting_started">Einstieg in CSS</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Styling_a_bio_page">Herausforderung: Gestaltung einer Biografie-Seite</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Basic_selectors">Grundlagen der CSS-Selektoren</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Attribute_selectors">Attribut-Selektoren</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Pseudo_classes_and_elements">Pseudoklassen und Pseudoelemente</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Combinators">Kombinatoren</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Box_model">Das Box-Modell</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Handling_conflicts">Umgang mit Konflikten</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Values_and_units">CSS-Werte und -Einheiten</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Sizing">Größenbestimmung von Elementen in CSS</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Backgrounds_and_borders">Hintergründe und Rahmen</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Overflow">Überlaufender Inhalt</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Images_media_forms">Bilder, Medien und Formularelemente</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Tables">Tabellen stylen</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Debugging_CSS">Debugging CSS</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Fundamental_CSS_comprehension">Herausforderung: Grundlegendes CSS-Verständnis</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Fancy_letterheaded_paper">Herausforderung: Erstellung eines ansprechenden Briefpapiers</a></li><li><a href="/de/docs/Learn_web_development/Core/Styling_basics/Cool-looking_box">Herausforderung: Eine cool aussehende Box</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/Text_styling">CSS-Textgestaltung</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/Text_styling/Fundamentals">Grundlegendes zur Text- und Schriftgestaltung</a></li><li><a href="/de/docs/Learn_web_development/Core/Text_styling/Styling_lists">Listen gestalten</a></li><li><a href="/de/docs/Learn_web_development/Core/Text_styling/Styling_links">Gestaltung von Links</a></li><li><a href="/de/docs/Learn_web_development/Core/Text_styling/Web_fonts">Webfonts</a></li><li><a href="/de/docs/Learn_web_development/Core/Text_styling/Typesetting_a_homepage">Herausforderung: Setzen einer Startseite für eine Gemeinschaftsschule</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/CSS_layout">CSS-Layout</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Introduction">Einführung in CSS-Layout</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Floats">Floats</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Positioning">Platzierung</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Flexbox">Flexbox</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Grids">CSS-Grid-Layout</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Responsive_Design">Responsives Design</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Media_queries">Grundlagen von Media Query</a></li><li><a href="/de/docs/Learn_web_development/Core/CSS_layout/Fundamental_Layout_Comprehension">Herausforderung: Grundlegendes Verständnis von Layouts</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/Scripting">Dynamisches Scripting mit JavaScript</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/Scripting/What_is_JavaScript">Was ist JavaScript?</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/A_first_splash">Erster Einblick in JavaScript</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/What_went_wrong">Was ist schiefgelaufen? JavaScript-Fehlerbehebung</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Variables">Speichern der benötigten Informationen — Variablen</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Math">Grundlegende Mathematik in JavaScript – Zahlen und Operatoren</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Strings">Umgang mit Text — Zeichenketten in JavaScript</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Useful_string_methods">Nützliche String-Methoden</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Arrays">Arrays</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Silly_story_generator">Herausforderung: Blödsinnige Geschichtengenerator</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Conditionals">Entscheidungen in Ihrem Code treffen — Konditionalen</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Loops">Code-Schleifen</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Functions">Funktionen — wiederverwendbare Codeblöcke</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Build_your_own_function">Erstellen Sie Ihre eigene Funktion</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Return_values">Funktionsrückgabewerte</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Events">Einführung in Ereignisse</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Event_bubbling">Ereignis-Bubbling</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Image_gallery">Herausforderung: Bildergalerie</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Object_basics">JavaScript-Objektgrundlagen</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/DOM_scripting">Einführung in DOM-Scripting</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Network_requests">Netzwerkanfragen mit JavaScript</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/JSON">Arbeiten mit JSON</a></li><li><a href="/de/docs/Learn_web_development/Core/Scripting/Debugging_JavaScript">Debugging JavaScript and handling errors</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries">JavaScript-Frameworks und -Bibliotheken</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/Introduction">Einführung in client-seitige Frameworks</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/Main_features">Hauptmerkmale von Frameworks</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started">Erste Schritte mit React</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_todo_list_beginning">Beginn unserer React To-Do-Liste</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_components">Komponenten in unserer React-App erstellen</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_events_state">React Interaktivität: Events und State</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering">Reaktivität in React: Bearbeiten, Filtern, bedingtes Rendern</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility">Barrierefreiheit in React</a></li><li><a href="/de/docs/Learn_web_development/Core/Frameworks_libraries/React_resources">React-Ressourcen</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Core/Accessibility">Barrierefreiheit</a></summary><ol><li><a href="/de/docs/Learn_web_development/Core/Accessibility/What_is_accessibility">Was ist Barrierefreiheit?</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/Tooling">Barrierefreiheitstools und unterstützende Technologien</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/HTML">HTML: Eine gute Grundlage für Barrierefreiheit</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript">CSS and JavaScript Zugänglichkeitsbest Practices</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/WAI-ARIA_basics">WAI-ARIA Grundlagen</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/Multimedia">Barrierefreie Multimedia-Inhalte</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/Mobile">Mobile Accessibility</a></li><li><a href="/de/docs/Learn_web_development/Core/Accessibility/Accessibility_troubleshooting">Herausforderung: Barrierefreiheits-Fehlerbehebung</a></li></ol></details></li><li><a href="/de/docs/Learn_web_development/Core/Design_for_developers">Design für Entwickler:innen</a></li><li><a href="/de/docs/Learn_web_development/Core/Version_control">Versionskontrolle</a></li><li class="section"><a href="/de/docs/Learn_web_development/Extensions">Erweiterungsmodule</a></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects">Advanced JavaScript objects</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes">Objektprototypen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming">Objektorientierte Programmierung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Classes_in_JavaScript">Klassen in JavaScript</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_building_practice">Objektbaupraxis</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Adding_bouncing_balls_features">Herausforderung: Hinzufügen von Funktionen zu unserem hüpfenden Ball-Demo</a></li></ol></details></li><li class="toggle"><details open=""><summary><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs">Client-seitige Web-APIs</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Introduction">Einführung in Web-APIs</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Video_and_audio_APIs">Video- und Audio-APIs</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics">Zeichnen von Grafiken</a></li><li><em><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage" aria-current="page">Client-seitiger Speicher</a></em></li><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs">Third-party APIs</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Async_JS">Asynchrones JavaScript</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Async_JS/Introducing">Einführung in asynchrones JavaScript</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Async_JS/Promises">Anleitung zur Verwendung von Promises</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Async_JS/Implementing_a_promise-based_API">Wie man eine Promise-basierte API implementiert</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Async_JS/Introducing_workers">Einführung in Worker</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Async_JS/Sequencing_animations">Herausforderung: Animationen sequenzieren</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Forms">Webformulare — Arbeiten mit Benutzerdaten</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Your_first_form">Ihr erstes Formular</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form">Wie man ein Webformular strukturiert</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls">Grundlegende native Formularsteuerungen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/HTML5_input_types">Die HTML5-Eingabetypen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Other_form_controls">Andere Formularelemente</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Styling_web_forms">Styling von Webformularen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Advanced_form_styling">Fortgeschrittenes Formular-Styling</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/UI_pseudo-classes">UI-Pseudoklassen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Form_validation">Client-seitige Formularvalidierung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data">Senden von Formulardaten</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Client-side_tools">Verständnis für clientseitige Tools</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_tools/Overview">Überblick über Client-seitige Tools</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_tools/Package_management">Grundlagen des Paketmanagements</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_tools/Introducing_complete_toolchain">Einführung in eine vollständige Werkzeugkette</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Client-side_tools/Deployment">Bereitstellung unserer App</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Server-side">Serverseitige Programmierung</a></summary><ol><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps">Erste Schritte auf der Serverseite</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction">Einführung in die Server-Seite</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview">Überblick über Client-Server</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Web_frameworks">Server-seitige Web-Frameworks</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security">Website-Sicherheit</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django">Django Web-Framework (Python)</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Introduction">Einführung in Django</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/development_environment">Einrichten einer Django-Entwicklungsumgebung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Tutorial_local_library_website">Django Tutorial: Die Website der lokalen Bibliothek</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website">Django-Tutorial Teil 2: Erstellen einer Skelett-Website</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Models">Django Tutorial Teil 3: Verwenden von Modellen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Admin_site">Django Tutorial Teil 4: Die Django Admin-Seite</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Home_page">Django Tutorial Teil 5: Erstellen unserer Homepage</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Generic_views">Django Tutorial Teil 6: Generische Listen- und Detailansichten</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Sessions">Django-Tutorial Teil 7: Sitzungs-Framework</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Authentication">Django-Tutorial Teil 8: Benutzer-Authentifizierung und -Berechtigungen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Forms">Django Tutorial Teil 9: Arbeiten mit Formularen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Testing">Django Tutorial Teil 10: Testen einer Django-Webanwendung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/Deployment">Django-Tutorial Teil 11: Bereitstellung von Django für die Produktion</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/web_application_security">Django Webanwendungssicherheit</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Django/django_assessment_blog">Bewertung: DIY Django Mini-Blog</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs">Express Web-Framework (Node.js)</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction">Einführung in Express/Node</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/development_environment">Einrichten einer Node-Entwicklungsumgebung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: Die Website der lokalen Bibliothek</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/skeleton_website">Express-Tutorial Teil 2: Erstellen einer Skelett-Website</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/mongoose">Express-Tutorial Teil 3: Verwendung einer Datenbank (mit Mongoose)</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes">Express Tutorial Teil 4: Routen und Controller</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Teil 5: Bibliotheksdaten anzeigen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/forms">Express Tutorial Teil 6: Arbeiten mit Formularen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/deployment">Express Tutorial Teil 7: Bereitstellung im Produktionsumfeld</a></li></ol></details></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Performance">Web-Performance</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Performance/why_web_performance">Das "Warum" der Web-Performance</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/What_is_web_performance">Was ist Web-Performance?</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/Perceived_performance">Wahrgenommene Leistung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/Measuring_performance">Leistungsmessung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/Multimedia">Multimedia: Bilder</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/video">Multimedia: video</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/JavaScript">JavaScript-Leistungsoptimierung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/HTML">HTML-Performance-Optimierung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/CSS">CSS-Leistungsoptimierung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Performance/business_case_for_performance">Der geschäftliche Nutzen der Web-Performance</a></li></ol></details></li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Extensions/Testing">Tests</a></summary><ol><li><a href="/de/docs/Learn_web_development/Extensions/Testing/Introduction">Einführung in das Cross-Browser-Testing</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Testing/Testing_strategies">Strategien zur Durchführung von Tests</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Testing/HTML_and_CSS">Umgang mit häufigen HTML- und CSS-Problemen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Testing/Feature_detection">Implementierung der Funktionsprüfung</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Testing/Automated_testing">Einführung in automatisiertes Testen</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Testing/Your_own_automation_environment">Einrichtung Ihrer eigenen Testautomatisierungsumgebung</a></li></ol></details></li><li><a href="/de/docs/Learn_web_development/Extensions/Transform_animate">CSS transformieren und animieren</a></li><li><a href="/de/docs/Learn_web_development/Extensions/Security_privacy">Sicherheit und Datenschutz</a></li><li class="section">Weitere Ressourcen</li><li class="toggle"><details><summary><a href="/de/docs/Learn_web_development/Howto">Häufige Probleme lösen</a></summary><ol><li><a href="/de/docs/Learn_web_development/Howto/Solve_HTML_problems">Häufige HTML-Probleme lösen</a></li><li><a href="/de/docs/Learn_web_development/Howto/Solve_CSS_problems">Häufige CSS-Probleme lösen</a></li><li><a href="/de/docs/Learn_web_development/Howto/Solve_JavaScript_problems">Häufige JavaScript-Probleme lösen</a></li><li><a href="/de/docs/Learn_web_development/Howto/Web_mechanics">Webmechanik</a></li><li><a href="/de/docs/Learn_web_development/Howto/Tools_and_setup">Tools und Einrichtung</a></li><li><a href="/de/docs/Learn_web_development/Howto/Design_and_accessibility">Design und Barrierefreiheit</a></li></ol></details></li><li><a href="/de/docs/Learn_web_development/About">Über</a></li><li><a href="/de/docs/Learn_web_development/Educators">Ressourcen für Lehrkräfte</a></li><li><a href="/de/docs/Learn_web_development/Changelog">Änderungsprotokoll</a></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 diesem Artikel</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#client-seitiger_speicher">Client-seitiger Speicher?</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speichern_einfacher_daten_–_web_storage">Speichern einfacher Daten – Web Storage</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speichern_komplexer_daten_–_indexeddb">Speichern komplexer Daten – IndexedDB</a></li><li class="document-toc-item "><a class="document-toc-link" href="#offline-asset-speicherung">Offline-Asset-Speicherung</a></li><li class="document-toc-item "><a class="document-toc-link" href="#zusammenfassung">Zusammenfassung</a></li><li class="document-toc-item "><a class="document-toc-link" href="#siehe_auch">Siehe auch</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="de"><header><h1>Client-seitiger Speicher</h1></header><div class="section-content"><ul class="prev-next"><li><a class="button secondary" href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics"><span class="button-wrap"> Zurück </span></a></li><li><a class="button secondary" href="/de/docs/Learn_web_development/Extensions/Client-side_APIs"><span class="button-wrap"> Übersicht: Client-seitige Web-APIs</span></a></li><li><a class="button secondary" href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs"><span class="button-wrap"> Weiter </span></a></li></ul> <p>Moderne Webbrowser unterstützen eine Vielzahl von Möglichkeiten, wie Websites Daten auf dem Rechner des Nutzers speichern und bei Bedarf abrufen können – mit der Erlaubnis des Nutzers. Dies ermöglicht Ihnen, Daten für die langfristige Speicherung zu speichern, Seiten oder Dokumente für die Offline-Nutzung zu sichern, nutzerspezifische Einstellungen für Ihre Website zu behalten und mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Techniken.</p> <figure class="table-container"><table> <tbody> <tr> <th scope="row">Voraussetzungen:</th> <td> Vertrautheit mit <a href="/de/docs/Learn_web_development/Core/Structuring_content">HTML</a>, <a href="/de/docs/Learn_web_development/Core/Styling_basics">CSS</a> und <a href="/de/docs/Learn_web_development/Core/Scripting">JavaScript</a>, insbesondere den <a href="/de/docs/Learn_web_development/Core/Scripting/Object_basics">JavaScript-Objekt-Grundlagen</a> und der grundlegenden API-Abdeckung wie <a href="/de/docs/Learn_web_development/Core/Scripting/DOM_scripting">DOM-Scripting</a> und <a href="/de/docs/Learn_web_development/Core/Scripting/Network_requests">Netzwerkanfragen</a>. </td> </tr> <tr> <th scope="row">Lernziele:</th> <td> <ul> <li>Die Konzepte des client-seitigen Speichers und welche Schlüsseltechnologien dies ermöglichen – Web Storage API, Cookies, Cache API und die IndexedDB API.</li> <li>Wichtige Anwendungsfälle – Zustand zwischen Neuladungen aufrechterhalten, Login- und Nutzerpersonalisierungsdaten beibehalten und lokale/offline Arbeit.</li> <li>Web Storage für einfache Schlüssel-Wert-Paar-Speicherungen verwenden, gesteuert durch JavaScript.</li> <li>Die Verwendung von IndexedDB zum Speichern komplexerer, strukturierter Daten.</li> <li>Die Verwendung der Cache API und Service Worker für Offline-Anwendungsfälle.</li> </ul> </td> </tr> </tbody> </table></figure></div><section aria-labelledby="client-seitiger_speicher"><h2 id="client-seitiger_speicher"><a href="#client-seitiger_speicher">Client-seitiger Speicher?</a></h2><div class="section-content"><p>An anderer Stelle im MDN-Lernbereich haben wir über den Unterschied zwischen <a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview#static_sites">statischen Websites</a> und <a href="/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview#dynamic_sites">dynamischen Websites</a> gesprochen. Die meisten großen modernen Websites sind dynamisch – sie speichern Daten auf dem Server mithilfe einer Datenbank (serverseitiger Speicher) und führen <a href="/de/docs/Learn_web_development/Extensions/Server-side">serverseitigen</a> Code aus, um die benötigten Daten abzurufen, sie in statische Seitentemplates einzufügen und das resultierende HTML dem Client zur Anzeige im Browser des Nutzers bereitzustellen.</p> <p>Client-seitiger Speicher funktioniert nach ähnlichen Prinzipien, hat jedoch unterschiedliche Anwendungsfälle. Er besteht aus JavaScript-APIs, die Ihnen erlauben, Daten auf dem Client (d.h. auf dem Rechner des Nutzers) zu speichern und bei Bedarf abzurufen. Dies hat viele verschiedene Anwendungen, wie:</p> <ul> <li>Personalisierung von Seiteneinstellungen (z. B. Anzeige der Auswahl eines Nutzers zu benutzerdefinierten Widgets, Farbschema oder Schriftgröße).</li> <li>Beibehalten früherer Website-Aktivitäten (z. B. Speichern der Inhalte eines Warenkorbs aus einer früheren Sitzung, Erinnern daran, ob ein Nutzer zuvor eingeloggt war).</li> <li>Lokales Speichern von Daten und Assets, damit eine Seite schneller (und möglicherweise kostengünstiger) heruntergeladen werden kann oder ohne Netzwerkverbindung nutzbar ist.</li> <li>Lokales Speichern von von Webanwendungen generierten Dokumenten zur Offline-Nutzung</li> </ul> <p>Häufig werden client-seitiger und server-seitiger Speicher zusammen verwendet. Zum Beispiel könnten Sie eine Reihe von Musikdateien herunterladen (vielleicht genutzt von einem Webspiel oder einer Musikplayer-Anwendung), sie in einer client-seitigen Datenbank speichern und bei Bedarf abspielen. Die Nutzer müssten die Musikdateien nur einmal herunterladen – bei späteren Besuchen würden sie stattdessen aus der Datenbank abgerufen.</p> <div class="notecard note"> <p><strong>Hinweis:</strong> Es gibt Einschränkungen hinsichtlich der Menge an Daten, die Sie mit client-seitigen Speicher-APIs speichern können (möglicherweise sowohl pro individueller API als auch kumulativ); das genaue Limit variiert je nach Browser und möglicherweise basierend auf den Einstellungen des Nutzers. Weitere Informationen finden Sie unter <a href="/de/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria">Speicherquoten und Auslöschkriterien für den Browser</a>.</p> </div></div></section><section aria-labelledby="altmodisch_cookies"><h3 id="altmodisch_cookies"><a href="#altmodisch_cookies">Altmodisch: Cookies</a></h3><div class="section-content"><p>Das Konzept des client-seitigen Speichers gibt es schon lange. Seit den frühen Tagen des Webs haben Websites <a href="/de/docs/Web/HTTP/Cookies">Cookies</a> genutzt, um Informationen zur Personalisierung der Nutzererfahrung auf Websites zu speichern. Sie sind die älteste Form des client-seitigen Speichers, der im Web weit verbreitet ist.</p> <p>Heutzutage gibt es einfachere Mechanismen zur Speicherung client-seitiger Daten, daher werden wir Ihnen in diesem Artikel nicht beibringen, wie man Cookies verwendet. Dies bedeutet jedoch nicht, dass Cookies im modernen Web völlig nutzlos sind – sie werden weiterhin häufig verwendet, um Daten im Zusammenhang mit Nutzerpersonalisierung und -zustand zu speichern, z. B. Sitzungs-IDs und Zugangs-Token. Weitere Informationen zu Cookies finden Sie in unserem Artikel <a href="/de/docs/Web/HTTP/Cookies">Verwendung von HTTP-Cookies</a>.</p></div></section><section aria-labelledby="modern_web_storage_und_indexeddb"><h3 id="modern_web_storage_und_indexeddb"><a href="#modern_web_storage_und_indexeddb">Modern: Web Storage und IndexedDB</a></h3><div class="section-content"><p>Die oben erwähnten "einfacheren" Funktionen sind wie folgt:</p> <ul> <li>Die <a href="/de/docs/Web/API/Web_Storage_API">Web Storage API</a> bietet einen Mechanismus zum Speichern und Abrufen kleinerer Datenitems, die aus einem Namen und einem entsprechenden Wert bestehen. Dies ist nützlich, wenn Sie nur einige einfache Daten speichern müssen, wie den Namen des Nutzers, ob er eingeloggt ist, welche Farbe für den Hintergrund des Bildschirms verwendet werden soll, usw.</li> <li>Die <a href="/de/docs/Web/API/IndexedDB_API">IndexedDB API</a> stellt dem Browser ein vollständiges Datenbanksystem zur Verfügung, um komplexe Daten zu speichern. Dies kann verwendet werden für Dinge von vollständigen Datenbeständen von Kunden bis hin zu komplexen Datentypen wie Audio- oder Videodateien.</li> </ul> <p>Sie werden mehr über diese APIs im Folgenden lernen.</p></div></section><section aria-labelledby="die_cache_api"><h3 id="die_cache_api"><a href="#die_cache_api">Die Cache API</a></h3><div class="section-content"><p>Die <a href="/de/docs/Web/API/Cache"><code>Cache</code></a> API ist dafür ausgelegt, HTTP-Antworten auf bestimmte Anfragen zu speichern, und ist sehr nützlich für Dinge wie das Speichern von Website-Assets offline, damit die Seite auch ohne Netzwerkverbindung genutzt werden kann. Die Cache API wird normalerweise in Kombination mit der <a href="/de/docs/Web/API/Service_Worker_API">Service Worker API</a> verwendet, obwohl das nicht zwingend notwendig ist.</p> <p>Die Verwendung von Cache und Service Workern ist ein fortgeschrittenes Thema, und wir werden es in diesem Artikel nicht im Detail behandeln, obwohl wir ein Beispiel im Abschnitt <a href="#offline-asset-speicherung">Offline-Asset-Speicherung</a> weiter unten zeigen werden.</p></div></section><section aria-labelledby="speichern_einfacher_daten_–_web_storage"><h2 id="speichern_einfacher_daten_–_web_storage"><a href="#speichern_einfacher_daten_–_web_storage">Speichern einfacher Daten – Web Storage</a></h2><div class="section-content"><p>Die <a href="/de/docs/Web/API/Web_Storage_API">Web Storage API</a> ist sehr einfach zu verwenden – Sie speichern einfache Name/Wert-Paare von Daten (beschränkt auf Strings, Zahlen usw.) und rufen diese Werte bei Bedarf ab.</p></div></section><section aria-labelledby="grundlegende_syntax"><h3 id="grundlegende_syntax"><a href="#grundlegende_syntax">Grundlegende Syntax</a></h3><div class="section-content"><p>Lassen Sie uns Ihnen zeigen, wie:</p> <ol> <li> <p>Besuchen Sie zunächst unser <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html" class="external" target="_blank">leeres Web-Storage-Template</a> auf GitHub (öffnen Sie dies in einem neuen Tab).</p> </li> <li> <p>Öffnen Sie die JavaScript-Konsole der Entwicklerwerkzeuge Ihres Browsers.</p> </li> <li> <p>Alle Daten Ihres Webspeichers sind in zwei objektähnlichen Strukturen im Browser enthalten: <a href="/de/docs/Web/API/Window/sessionStorage"><code>sessionStorage</code></a> und <a href="/de/docs/Web/API/Window/localStorage"><code>localStorage</code></a>. Das erste speichert Daten für die Dauer, in der der Browser geöffnet ist (die Daten gehen verloren, wenn der Browser geschlossen wird), und das zweite speichert Daten auch noch nach dem Schließen und erneuten Öffnen des Browsers. Wir werden in diesem Artikel das zweite verwenden, da es im Allgemeinen nützlicher ist.</p> <p>Die Methode <a href="/de/docs/Web/API/Storage/setItem"><code>Storage.setItem()</code></a> ermöglicht Ihnen, ein Datenitem in den Speicher zu speichern – sie benötigt zwei Parameter: den Namen des Items und seinen Wert. Versuchen Sie, dies in Ihre JavaScript-Konsole einzugeben (Ändern Sie den Wert in Ihren eigenen Namen, wenn Sie möchten!):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>localStorage.setItem("name", "Chris"); </code></pre></div> </li> <li> <p>Die Methode <a href="/de/docs/Web/API/Storage/getItem"><code>Storage.getItem()</code></a> benötigt einen Parameter – den Namen eines Datenitems, das Sie abrufen möchten – und gibt den Wert des Items zurück. Geben Sie nun diese Zeilen in Ihre JavaScript-Konsole ein:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>let myName = localStorage.getItem("name"); myName; </code></pre></div> <p>Beim Eingeben der zweiten Zeile sollten Sie sehen, dass die Variable <code>myName</code> nun den Wert des <code>name</code> Datenitems enthält.</p> </li> <li> <p>Die Methode <a href="/de/docs/Web/API/Storage/removeItem"><code>Storage.removeItem()</code></a> benötigt einen Parameter – den Namen eines Datenitems, das Sie entfernen möchten – und entfernt dieses Item aus dem Webspeicher. Geben Sie die folgenden Zeilen in Ihre JavaScript-Konsole ein:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>localStorage.removeItem("name"); myName = localStorage.getItem("name"); myName; </code></pre></div> <p>Die dritte Zeile sollte nun <code>null</code> zurückgeben – das <code>name</code> Item existiert nicht mehr im Webspeicher.</p> </li> </ol></div></section><section aria-labelledby="die_daten_bleiben_bestehen!"><h3 id="die_daten_bleiben_bestehen!"><a href="#die_daten_bleiben_bestehen!">Die Daten bleiben bestehen!</a></h3><div class="section-content"><p>Ein wesentliches Merkmal des Webspeichers ist, dass die Daten zwischen Seitenladevorgängen bestehen bleiben (und sogar nach dem Herunterfahren des Browsers, im Fall von <code>localStorage</code>). Lassen Sie uns dies in Aktion sehen.</p> <ol> <li> <p>Öffnen Sie unser leeres Web-Storage-Template erneut, diesmal jedoch in einem anderen Browser als dem, in dem Sie dieses Tutorial geöffnet haben! Dies macht es einfacher, damit umzugehen.</p> </li> <li> <p>Geben Sie diese Zeilen in die JavaScript-Konsole des Browsers ein:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>localStorage.setItem("name", "Chris"); let myName = localStorage.getItem("name"); myName; </code></pre></div> <p>Sie sollten das zurückgegebene <code>name</code> Item sehen.</p> </li> <li> <p>Schließen Sie nun den Browser und öffnen Sie ihn wieder.</p> </li> <li> <p>Geben Sie die folgenden Zeilen erneut ein:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>let myName = localStorage.getItem("name"); myName; </code></pre></div> <p>Sie sollten sehen, dass der Wert immer noch verfügbar ist, obwohl der Browser geschlossen und dann wieder geöffnet wurde.</p> </li> </ol></div></section><section aria-labelledby="separater_speicher_für_jede_domäne"><h3 id="separater_speicher_für_jede_domäne"><a href="#separater_speicher_für_jede_domäne">Separater Speicher für jede Domäne</a></h3><div class="section-content"><p>Es gibt einen separaten Datenspeicher für jede Domäne (jede separate Webadresse, die im Browser geladen wird). Sie werden sehen, dass, wenn Sie zwei Websites laden (sagen wir google.com und amazon.com) und versuchen, ein Item auf einer Website zu speichern, es für die andere Website nicht verfügbar ist.</p> <p>Das macht Sinn – Sie können sich die Sicherheitsprobleme vorstellen, die auftreten würden, wenn Websites die Daten anderer Websites sehen könnten!</p></div></section><section aria-labelledby="ein_umfangreicheres_beispiel"><h3 id="ein_umfangreicheres_beispiel"><a href="#ein_umfangreicheres_beispiel">Ein umfangreicheres Beispiel</a></h3><div class="section-content"><p>Lassen Sie uns dieses neue Wissen anwenden, indem wir ein funktionierendes Beispiel schreiben, um Ihnen eine Vorstellung davon zu geben, wie Webspeicher verwendet werden kann. Unser Beispiel ermöglicht es Ihnen, einen Namen einzugeben, nach dem die Seite aktualisiert wird, um Ihnen eine personalisierte Begrüßung zu geben. Dieser Zustand bleibt auch bei Seiten-/Browserneuladungen bestehen, da der Name im Webspeicher gespeichert wird.</p> <p>Sie finden das Beispiel-HTML unter <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/web-storage/personal-greeting.html" class="external" target="_blank">personal-greeting.html</a> – es enthält eine Website mit einer Kopfzeile, einem Inhalt und einer Fußzeile sowie ein Formular zur Eingabe Ihres Namens.</p> <p><img src="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage/web-storage-demo.png" alt="Ein Screenshot einer Website, die Abschnitte für einen Header, Inhalt und eine Fußzeile hat. Der Header hat einen Begrüßungstext auf der linken Seite und einen Button mit der Bezeichnung 'vergessen' auf der rechten Seite. Der Inhalt hat eine Überschrift gefolgt von zwei Absätzen mit Blindtext. Der Footer liest 'Copyright nobody. Use the code as you like'." width="1024" height="550" loading="lazy"></p> <p>Lassen Sie uns das Beispiel aufbauen, damit Sie verstehen, wie es funktioniert.</p> <ol> <li> <p>Erstellen Sie zuerst eine lokale Kopie unserer <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/web-storage/personal-greeting.html" class="external" target="_blank">personal-greeting.html</a> Datei in einem neuen Verzeichnis auf Ihrem Computer.</p> </li> <li> <p>Beachten Sie als Nächstes, wie unser HTML auf eine JavaScript-Datei namens <code>index.js</code> verweist, mit einer Zeile wie <code><script src="index.js" defer></script></code>. Diese müssen wir erstellen und unseren JavaScript-Code darin schreiben. Erstellen Sie eine <code>index.js</code> Datei im selben Verzeichnis wie Ihre HTML-Datei.</p> </li> <li> <p>Wir beginnen damit, Referenzen zu allen HTML-Features zu erstellen, die wir in diesem Beispiel manipulieren müssen – wir erstellen sie alle als Konstanten, da sich diese Referenzen im Lebenszyklus der App nicht ändern müssen. Fügen Sie die folgenden Zeilen zu Ihrer JavaScript-Datei hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// create needed constants const rememberDiv = document.querySelector(".remember"); const forgetDiv = document.querySelector(".forget"); const form = document.querySelector("form"); const nameInput = document.querySelector("#entername"); const submitBtn = document.querySelector("#submitname"); const forgetBtn = document.querySelector("#forgetname"); const h1 = document.querySelector("h1"); const personalGreeting = document.querySelector(".personal-greeting"); </code></pre></div> </li> <li> <p>Als Nächstes müssen wir einen kleinen Ereignis-Listener hinzufügen, um zu verhindern, dass das Formular tatsächlich versendet wird, wenn der Absendebutton gedrückt wird, da dies nicht das Verhalten ist, das wir wünschen. Fügen Sie dieses Snippet unter Ihren vorherigen Code hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Stop the form from submitting when a button is pressed form.addEventListener("submit", (e) => e.preventDefault()); </code></pre></div> </li> <li> <p>Nun müssen wir einen Ereignis-Listener hinzufügen, dessen Handlerfunktion ausgeführt wird, wenn der "Say hello"-Button geklickt wird. Die Kommentare erklären detailliert, was jeder Teil macht, aber im Wesentlichen nehmen wir hier den Namen, den der Nutzer in das Text-Eingabefeld eingegeben hat und speichern ihn im Webspeicher mit <code>setItem()</code>, dann führen wir eine Funktion namens <code>nameDisplayCheck()</code> aus, die das tatsächliche Webseiten-Text Update behandelt. Fügen Sie dies unten in Ihren Code ein:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// run function when the 'Say hello' button is clicked submitBtn.addEventListener("click", () => { // store the entered name in web storage localStorage.setItem("name", nameInput.value); // run nameDisplayCheck() to sort out displaying the personalized greetings and updating the form display nameDisplayCheck(); }); </code></pre></div> </li> <li> <p>An diesem Punkt benötigen wir auch einen Ereignishandler, der eine Funktion ausführt, wenn der "Vergessen"-Button geklickt wird – dieser wird nur angezeigt, nachdem der "Say hello"-Button geklickt wurde (die zwei Formularzustände wechseln sich ab). In dieser Funktion entfernen wir das <code>name</code> Item aus dem Webspeicher mit <code>removeItem()</code>, dann führen wir erneut <code>nameDisplayCheck()</code> aus, um die Anzeige zu aktualisieren. Fügen Sie dies am Ende hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// run function when the 'Forget' button is clicked forgetBtn.addEventListener("click", () => { // Remove the stored name from web storage localStorage.removeItem("name"); // run nameDisplayCheck() to sort out displaying the generic greeting again and updating the form display nameDisplayCheck(); }); </code></pre></div> </li> <li> <p>Nun ist es an der Zeit die Funktion <code>nameDisplayCheck()</code> selbst zu definieren. Hier prüfen wir, ob das <code>name</code> Item im Webspeicher gespeichert wurde, indem wir <code>localStorage.getItem('name')</code> als Bedingungstest verwenden. Wenn der Name gespeichert wurde, wird dieser Aufruf zu <code>true</code> ausgewertet; wenn nicht, wird der Aufruf zu <code>false</code> ausgewertet. Wenn der Aufruf zu <code>true</code> ausgewertet wird, zeigen wir eine personalisierte Begrüßung an, zeigen den "vergessen"-Teil des Formulars an, und verbergen den "Say hello"-Teil des Formulars. Wird der Aufruf zu <code>false</code> ausgewertet, wird eine generische Begrüßung angezeigt und das Gegenteil gemacht. Setzen Sie den folgenden Code erneut unten ein:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// define the nameDisplayCheck() function function nameDisplayCheck() { // check whether the 'name' data item is stored in web Storage if (localStorage.getItem("name")) { // If it is, display personalized greeting const name = localStorage.getItem("name"); h1.textContent = `Welcome, ${name}`; personalGreeting.textContent = `Welcome to our website, ${name}! We hope you have fun while you are here.`; // hide the 'remember' part of the form and show the 'forget' part forgetDiv.style.display = "block"; rememberDiv.style.display = "none"; } else { // if not, display generic greeting h1.textContent = "Welcome to our website "; personalGreeting.textContent = "Welcome to our website. We hope you have fun while you are here."; // hide the 'forget' part of the form and show the 'remember' part forgetDiv.style.display = "none"; rememberDiv.style.display = "block"; } } </code></pre></div> </li> <li> <p>Zu guter Letzt müssen wir die Funktion <code>nameDisplayCheck()</code> ausführen, wenn die Seite geladen wird. Wenn wir dies nicht tun, wird die personalisierte Begrüßung nicht über Seitenladevorgänge hinweg bestehen bleiben. Fügen Sie das Folgende am Ende Ihres Codes hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>nameDisplayCheck(); </code></pre></div> </li> </ol> <p>Ihr Beispiel ist fertig – gut gemacht! Alles, was noch fehlt, ist, Ihren Code zu speichern und Ihre HTML-Seite in einem Browser zu testen. Sie können unsere <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/personal-greeting.html" class="external" target="_blank">fertige Version hier live in Aktion sehen</a>.</p> <div class="notecard note"> <p><strong>Hinweis:</strong> Es gibt ein weiteres, etwas komplexeres Beispiel, das Sie unter <a href="/de/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Verwendung der Web Storage API</a> erkunden können.</p> </div> <div class="notecard note"> <p><strong>Hinweis:</strong> In der Zeile <code><script src="index.js" defer></script></code> des Quellcodes unserer fertigen Version gibt das <code>defer</code> Attribut an, dass der Inhalt des <a href="/de/docs/Web/HTML/Element/script"><code><script></code></a> Elements nicht ausgeführt wird, bis die Seite fertig geladen ist.</p> </div></div></section><section aria-labelledby="speichern_komplexer_daten_–_indexeddb"><h2 id="speichern_komplexer_daten_–_indexeddb"><a href="#speichern_komplexer_daten_–_indexeddb">Speichern komplexer Daten – IndexedDB</a></h2><div class="section-content"><p>Die <a href="/de/docs/Web/API/IndexedDB_API">IndexedDB API</a> (manchmal abgekürzt als IDB) ist ein vollständiges Datenbanksystem, das im Browser verfügbar ist, in dem Sie komplexe, verwandte Daten speichern können, deren Typen nicht auf einfache Werte wie Strings oder Zahlen beschränkt sind. Sie können Videos, Bilder und so ziemlich alles andere in einer IndexedDB-Instanz speichern.</p> <p>Die IndexedDB API ermöglicht es Ihnen, eine Datenbank zu erstellen und dann Objekt-Speicher innerhalb dieser Datenbank zu erstellen. Objekt-Speicher sind wie Tabellen in einer relationalen Datenbank, und jeder Objekt-Speicher kann eine Anzahl von Objekten enthalten. Um mehr über die IndexedDB API zu erfahren, siehe <a href="/de/docs/Web/API/IndexedDB_API/Using_IndexedDB">Verwendung von IndexedDB</a>.</p> <p>Allerdings hat dies seinen Preis: IndexedDB ist viel komplexer zu verwenden als die Web Storage API. In diesem Abschnitt werden wir wirklich nur an der Oberfläche dessen kratzen, wozu sie fähig ist, aber wir geben Ihnen genug, um anzufangen.</p></div></section><section aria-labelledby="ein_beispiel_zur_notizspeicherung"><h3 id="ein_beispiel_zur_notizspeicherung"><a href="#ein_beispiel_zur_notizspeicherung">Ein Beispiel zur Notizspeicherung</a></h3><div class="section-content"><p>Hier führen wir Sie durch ein Beispiel, das Ihnen ermöglicht, Notizen in Ihrem Browser zu speichern und sie wann immer Sie möchten anzusehen und zu löschen, indem Sie es für sich selbst aufbauen und die grundlegendsten Teile von IDB erklären, während wir fortfahren.</p> <p>Die App sieht ungefähr so aus:</p> <p><img src="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage/idb-demo.png" alt="IndexDB Notizen-Demo-Screenshot mit 4 Abschnitten. Der erste Abschnitt ist der Header. Der zweite Abschnitt listet alle Notizen auf, die erstellt wurden. Es gibt zwei Notizen, jede mit einem Löschen-Button. Ein dritter Abschnitt ist ein Formular mit 2 Eingabefeldern für 'Titel der Notiz' und 'Text der Notiz' und einem Button mit der Bezeichnung 'Neue Notiz erstellen'. Der untere Abschnitt Fußzeile liest 'Copyright nobody. Use the code as you like'." width="803" height="736" loading="lazy"></p> <p>Jede Notiz hat einen Titel und einen Textkörper, beide individuell bearbeitbar. Der JavaScript-Code, den wir im Folgenden durchgehen, enthält detaillierte Kommentare, die Ihnen helfen, zu verstehen, was vor sich geht.</p></div></section><section aria-labelledby="grundlagen_starten"><h3 id="grundlagen_starten"><a href="#grundlagen_starten">Grundlagen starten</a></h3><div class="section-content"><ol> <li>Erstellen Sie zunächst lokale Kopien unserer <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/index.html" class="external" target="_blank"><code>index.html</code></a>, <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/style.css" class="external" target="_blank"><code>style.css</code></a> und <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/index-start.js" class="external" target="_blank"><code>index-start.js</code></a> Dateien in einem neuen Verzeichnis auf Ihrer lokalen Maschine.</li> <li>Sehen Sie sich die Dateien an. Sie werden sehen, dass das HTML eine Website mit einer Kopfzeile und einer Fußzeile sowie einen Hauptinhaltbereich definiert, der einen Platz zum Anzeigen von Notizen und ein Formular zum Eingeben neuer Notizen in die Datenbank enthält. Das CSS sorgt für etwas Styling, um klarer zu machen, was vor sich geht. Die JavaScript-Datei enthält fünf deklarierte Konstanten, die Verweise auf das <a href="/de/docs/Web/HTML/Element/ul"><code><ul></code></a>-Element enthalten, in dem die Notizen angezeigt werden; die <a href="/de/docs/Web/HTML/Element/input"><code><input></code></a>-Elemente für Titel und Text, das <a href="/de/docs/Web/HTML/Element/form"><code><form></code></a> selbst und der <a href="/de/docs/Web/HTML/Element/button"><code><button></code></a>.</li> <li>Benennen Sie Ihre JavaScript-Datei in <code>index.js</code> um. Sie sind jetzt bereit, Code hinzuzufügen.</li> </ol></div></section><section aria-labelledby="datenbank-grundeinrichtung"><h3 id="datenbank-grundeinrichtung"><a href="#datenbank-grundeinrichtung">Datenbank-Grundeinrichtung</a></h3><div class="section-content"><p>Schauen wir uns nun an, was wir eigentlich tun müssen, um eine Datenbank einzurichten.</p> <ol> <li> <p>Fügen Sie unter den Konstantendeklarationen die folgenden Zeilen hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Create an instance of a db object for us to store the open database in let db; </code></pre></div> <p>Hier erklären wir eine Variable namens <code>db</code> – diese wird später verwendet, um ein Objekt zu speichern, das unsere Datenbank repräsentiert. Wir werden dies an einigen Stellen verwenden, also haben wir es hier global deklariert, um die Dinge zu erleichtern.</p> </li> <li> <p>Fügen Sie als Nächstes die folgenden Zeilen hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Open our database; it is created if it doesn't already exist // (see the upgradeneeded handler below) const openRequest = window.indexedDB.open("notes_db", 1); </code></pre></div> <p>Diese Zeile erstellt eine Anfrage zum Öffnen von Version <code>1</code> einer Datenbank namens <code>notes_db</code>. Wenn diese nicht bereits existiert, wird sie durch nachfolgenden Code für Sie erstellt. Sie werden dieses Anfrage-Muster sehr häufig in IndexedDB sehen. Datenbankoperationen benötigen Zeit. Sie möchten nicht, dass der Browser hängt, während Sie auf die Ergebnisse warten, also sind Datenbankoperationen <a href="/de/docs/Glossary/Asynchronous">asynchron</a>, was bedeutet, dass sie nicht sofort geschehen, sondern irgendwann in der Zukunft, und Sie werden benachrichtigt, wenn sie abgeschlossen sind.</p> <p>Um dies in IndexedDB zu handhaben, erstellen Sie ein Anforderungsobjekt (das wie Sie möchten genannt werden kann – wir haben es hier <code>openRequest</code> genannt, damit klar ist, wofür es ist). Sie verwenden dann Ereignis-Handler, um Code auszuführen, wenn die Anfrage abgeschlossen, fehlgeschlagen usw. ist. Dies werden Sie unten in Anwendung sehen.</p> <div class="notecard note"> <p><strong>Hinweis:</strong> Die Versionsnummer ist wichtig. Wenn Sie Ihre Datenbank aktualisieren möchten (z. B. durch Ändern der Tabellenstruktur), müssen Sie Ihren Code erneut mit einer erhöhten Versionsnummer ausführen, einem anderen im <code>upgradeneeded</code> Handler spezifizierten Schema (siehe unten) usw. Wir werden die Aktualisierung von Datenbanken in diesem Tutorial nicht behandeln.</p> </div> </li> <li> <p>Fügen Sie nun die folgenden Ereignis-Handler direkt unter Ihrer vorherigen Ergänzung hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// error handler signifies that the database didn't open successfully openRequest.addEventListener("error", () => console.error("Database failed to open"), ); // success handler signifies that the database opened successfully openRequest.addEventListener("success", () => { console.log("Database opened successfully"); // Store the opened database object in the db variable. This is used a lot below db = openRequest.result; // Run the displayData() function to display the notes already in the IDB displayData(); }); </code></pre></div> <p>Der <a href="/de/docs/Web/API/IDBRequest/error_event"><code>error</code></a> Ereignis-Handler wird ausgeführt, wenn das System zurückkommt und sagt, dass die Anfrage fehlgeschlagen ist. Dadurch können Sie auf dieses Problem reagieren. In unserem Beispiel drucken wir einfach eine Nachricht in die JavaScript-Konsole.</p> <p>Der <a href="/de/docs/Web/API/IDBRequest/success_event"><code>success</code></a> Ereignis-Handler wird ausgeführt, wenn die Anforderung erfolgreich abgeschlossen wurde, was bedeutet, dass die Datenbank erfolgreich geöffnet wurde. Wenn dies der Fall ist, wird ein Objekt, das die geöffnete Datenbank darstellt, in der <a href="/de/docs/Web/API/IDBRequest/result"><code>openRequest.result</code></a> Eigenschaft verfügbar, wodurch wir die Datenbank manipulieren können. Wir speichern dies in der <code>db</code> Variablen, die wir zuvor für die spätere Verwendung erstellt haben. Wir führen auch eine Funktion namens <code>displayData()</code> aus, die die Daten in der Datenbank innerhalb des <a href="/de/docs/Web/HTML/Element/ul"><code><ul></code></a> anzeigt. Wir führen sie jetzt aus, damit die in der Datenbank bereits vorhandenen Notizen sofort angezeigt werden, wenn die Seite geladen wird. Sie sehen <code>displayData()</code> später definiert.</p> </li> <li> <p>Schließlich für diesen Abschnitt fügen wir wahrscheinlich den wichtigsten Ereignis-Handler zur Einrichtung der Datenbank hinzu: <a href="/de/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event"><code>upgradeneeded</code></a>. Dieser Handler wird ausgeführt, wenn die Datenbank noch nicht eingerichtet wurde oder wenn die Datenbank mit einer höheren Versionsnummer als der in der vorhandenen gespeicherten Datenbank geöffnet wird (bei einem Upgrade). Fügen Sie den folgenden Code unter Ihrem vorherigen Handler hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Set up the database tables if this has not already been done openRequest.addEventListener("upgradeneeded", (e) => { // Grab a reference to the opened database db = e.target.result; // Create an objectStore in our database to store notes and an auto-incrementing key // An objectStore is similar to a 'table' in a relational database const objectStore = db.createObjectStore("notes_os", { keyPath: "id", autoIncrement: true, }); // Define what data items the objectStore will contain objectStore.createIndex("title", "title", { unique: false }); objectStore.createIndex("body", "body", { unique: false }); console.log("Database setup complete"); }); </code></pre></div> <p>Hier definieren wir das Schema (die Struktur) unserer Datenbank; das heißt, die Reihe von Spalten (oder Feldern), die sie enthält. Hier holen wir zuerst eine Referenz zur vorhandenen Datenbank aus der <code>result</code> Eigenschaft des Zielobjekts des Ereignisses (<code>e.target.result</code>), das das <code>request</code>-Objekt ist. Dies entspricht der Zeile <code>db = openRequest.result;</code> im <code>success</code>-Ereignis-Handler, aber wir müssen dies hier separat tun, weil der <code>upgradeneeded</code> Ereignis-Handler (falls erforderlich) vor dem <code>success</code> Ereignis-Handler ausgeführt wird, was bedeutet, dass der <code>db</code> Wert nicht verfügbar wäre, wenn wir dies nicht tun würden.</p> <p>Wir verwenden dann <a href="/de/docs/Web/API/IDBDatabase/createObjectStore"><code>IDBDatabase.createObjectStore()</code></a> zum Erstellen eines neuen Objekt-Speichers in unserer geöffneten Datenbank namens <code>notes_os</code>. Dies entspricht einer einzelnen Tabelle in einem konventionellen Datenbanksystem. Wir haben es den Namen Notizen gegeben und ein <code>autoIncrement</code> Schlüssel-Feld genannt <code>id</code> spezifiziert – in jedem neuen Datensatz wird dies automatisch mit einem inkrementierten Wert vergeben – der Entwickler muss dies nicht explizit festlegen. Als Schlüssel wird das Feld <code>id</code> verwendet, um Datensätze eindeutig zu identifizieren, wie z. B. beim Löschen oder Anzeigen eines Datensatzes.</p> <p>Wir erstellen auch zwei weitere Indizes (Felder) mit der Methode <a href="/de/docs/Web/API/IDBObjectStore/createIndex"><code>IDBObjectStore.createIndex()</code></a>: <code>title</code> (das einen Titel für jede Notiz enthalten wird) und <code>body</code> (das den Textkörper der Notiz enthalten wird).</p> </li> </ol> <p>Mit diesem Datenbankschema eingerichtet, wird jeder Datensatz, den wir der Datenbank hinzufügen, als ein Objekt entlang dieser Linien dargestellt:</p> <div class="code-example"><div class="example-header"><span class="language-name">json</span></div><pre class="brush: json notranslate"><code>{ "title": "Buy milk", "body": "Need both cows milk and soy.", "id": 8 } </code></pre></div></div></section><section aria-labelledby="hinzufügen_von_daten_zur_datenbank"><h3 id="hinzufügen_von_daten_zur_datenbank"><a href="#hinzufügen_von_daten_zur_datenbank">Hinzufügen von Daten zur Datenbank</a></h3><div class="section-content"><p>Schauen wir uns nun an, wie wir Datensätze zur Datenbank hinzufügen können. Dies wird über das Formular auf unserer Seite geschehen.</p> <p>Fügen Sie unter Ihrem vorherigen Ereignis-Handler die folgende Zeile hinzu, die einen <code>submit</code>-Ereignis-Handler festlegt, der eine Funktion namens <code>addData()</code> ausführt, wenn das Formular abgesendet wird (wenn der Absende-<a href="/de/docs/Web/HTML/Element/button"><code><button></code></a> gedrückt wird, was zu einer erfolgreichen Formularübermittlung führt):</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Create a submit event handler so that when the form is submitted the addData() function is run form.addEventListener("submit", addData); </code></pre></div> <p>Nun definieren wir die Funktion <code>addData()</code>. Fügen Sie diese unter Ihrer vorherigen Zeile hinzu:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Define the addData() function function addData(e) { // prevent default - we don't want the form to submit in the conventional way e.preventDefault(); // grab the values entered into the form fields and store them in an object ready for being inserted into the DB const newItem = { title: titleInput.value, body: bodyInput.value }; // open a read/write db transaction, ready for adding the data const transaction = db.transaction(["notes_os"], "readwrite"); // call an object store that's already been added to the database const objectStore = transaction.objectStore("notes_os"); // Make a request to add our newItem object to the object store const addRequest = objectStore.add(newItem); addRequest.addEventListener("success", () => { // Clear the form, ready for adding the next entry titleInput.value = ""; bodyInput.value = ""; }); // Report on the success of the transaction completing, when everything is done transaction.addEventListener("complete", () => { console.log("Transaction completed: database modification finished."); // update the display of data to show the newly added item, by running displayData() again. displayData(); }); transaction.addEventListener("error", () => console.log("Transaction not opened due to error"), ); } </code></pre></div> <p>Dies ist ziemlich komplex; nutzen wir dies, um es herunterzubrechen:</p> <ul> <li>Wir führen <a href="/de/docs/Web/API/Event/preventDefault"><code>Event.preventDefault()</code></a> für das Ereignis-Objekt aus, um zu verhindern, dass das Formular tatsächlich auf herkömmliche Weise abgesendet wird (dies würde ein Seiten-Neuladen verursachen und die Erfahrung verderben).</li> <li>Wir erstellen ein Objekt, das einen Datensatz repräsentiert, der in die Datenbank eingefügt werden soll und mit Werten aus den Formulareingaben gefüllt wird. Beachten Sie, dass wir nicht explizit einen <code>id</code> Wert einbeziehen müssen – wie bereits erwähnt, wird dies automatisch gefüllt.</li> <li>Wir öffnen eine <code>readwrite</code> Transaktion gegen den <code>notes_os</code> Objektspeicher mit der Methode <a href="/de/docs/Web/API/IDBDatabase/transaction"><code>IDBDatabase.transaction()</code></a>. Dieses Transaktionsobjekt ermöglicht es uns, auf den Objektspeicher zuzugreifen, damit wir etwas damit tun können, z.B. einen neuen Datensatz hinzufügen.</li> <li>Wir greifen mit der Methode <a href="/de/docs/Web/API/IDBTransaction/objectStore"><code>IDBTransaction.objectStore()</code></a> auf den Objektspeicher zu und speichern das Ergebnis in der Variablen <code>objectStore</code>.</li> <li>Wir fügen den neuen Datensatz mit <a href="/de/docs/Web/API/IDBObjectStore/add"><code>IDBObjectStore.add()</code></a> zur Datenbank hinzu. Dies erstellt ein Anforderungsobjekt, so wie wir es zuvor gesehen haben.</li> <li>Wir fügen eine Reihe von Ereignis-Handlern zu den Objekten <code>request</code> und <code>transaction</code> hinzu, um Code an kritischen Punkten im Lebenszyklus auszuführen. Sobald die Anforderung erfolgreich war, löschen wir die Formulareingaben, um die nächste Notiz einzugeben. Sobald die Transaktion abgeschlossen ist, führen wir die <code>displayData()</code> Funktion erneut aus, um die Anzeige der Notizen auf der Seite zu aktualisieren.</li> </ul></div></section><section aria-labelledby="anzeigen_der_daten"><h3 id="anzeigen_der_daten"><a href="#anzeigen_der_daten">Anzeigen der Daten</a></h3><div class="section-content"><p>Wir haben <code>displayData()</code> bereits zweimal in unserem Code referenziert, also sollten wir es wahrscheinlich definieren. Fügen Sie dies zu Ihrem Code hinzu, unter der vorherigen Funktionsdefinition:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Define the displayData() function function displayData() { // Here we empty the contents of the list element each time the display is updated // If you didn't do this, you'd get duplicates listed each time a new note is added while (list.firstChild) { list.removeChild(list.firstChild); } // Open our object store and then get a cursor - which iterates through all the // different data items in the store const objectStore = db.transaction("notes_os").objectStore("notes_os"); objectStore.openCursor().addEventListener("success", (e) => { // Get a reference to the cursor const cursor = e.target.result; // If there is still another data item to iterate through, keep running this code if (cursor) { // Create a list item, h3, and p to put each data item inside when displaying it // structure the HTML fragment, and append it inside the list const listItem = document.createElement("li"); const h3 = document.createElement("h3"); const para = document.createElement("p"); listItem.appendChild(h3); listItem.appendChild(para); list.appendChild(listItem); // Put the data from the cursor inside the h3 and para h3.textContent = cursor.value.title; para.textContent = cursor.value.body; // Store the ID of the data item inside an attribute on the listItem, so we know // which item it corresponds to. This will be useful later when we want to delete items listItem.setAttribute("data-note-id", cursor.value.id); // Create a button and place it inside each listItem const deleteBtn = document.createElement("button"); listItem.appendChild(deleteBtn); deleteBtn.textContent = "Delete"; // Set an event handler so that when the button is clicked, the deleteItem() // function is run deleteBtn.addEventListener("click", deleteItem); // Iterate to the next item in the cursor cursor.continue(); } else { // Again, if list item is empty, display a 'No notes stored' message if (!list.firstChild) { const listItem = document.createElement("li"); listItem.textContent = "No notes stored."; list.appendChild(listItem); } // if there are no more cursor items to iterate through, say so console.log("Notes all displayed"); } }); } </code></pre></div> <p>Brechen wir dies erneut auseinander:</p> <ul> <li>Zuerst leeren wir den Inhalt des <a href="/de/docs/Web/HTML/Element/ul"><code><ul></code></a> Elements, bevor wir es dann mit dem aktualisierten Inhalt füllen. Wenn Sie dies nicht tun würden, würden Sie eine riesige Liste duplizierter Inhalte haben, die bei jedem Update hinzugefügt wird.</li> <li>Als Nächstes erhalten wir eine Referenz zum <code>notes_os</code> Objektspeicher mit <a href="/de/docs/Web/API/IDBDatabase/transaction"><code>IDBDatabase.transaction()</code></a> und <a href="/de/docs/Web/API/IDBTransaction/objectStore"><code>IDBTransaction.objectStore()</code></a> genauso, wie wir es in <code>addData()</code> getan haben, außer dass wir sie hier in einer Zeile verketten.</li> <li>Der nächste Schritt ist die Verwendung der Methode <a href="/de/docs/Web/API/IDBObjectStore/openCursor"><code>IDBObjectStore.openCursor()</code></a>, um eine Anfrage für einen Cursor zu öffnen – dies ist ein Konstrukt, das zum Durchlaufen der Datensätze in einem Objektspeicher verwendet werden kann. Wir verketten einen <code>success</code> Ereignis-Handler an das Ende dieser Zeile, um den Code prägnanter zu gestalten – wenn der Cursor erfolgreich zurückgegeben wird, wird der Handler ausgeführt.</li> <li>Wir erhalten eine Referenz auf den Cursor selbst (ein <a href="/de/docs/Web/API/IDBCursor"><code>IDBCursor</code></a> Objekt) mit <code>const cursor = e.target.result</code>.</li> <li>Als Nächstes prüfen wir, ob der Cursor einen Datensatz aus dem Datenspeicher enthält (<code>if (cursor){ }</code>) – wenn ja, erstellen wir einen DOM-Fragment, füllen es mit den Daten des Datensatzes und fügen es in die Seite ein (innerhalb des <code><ul></code> Elements). Wir fügen auch einen Löschen-Button hinzu, der, wenn er geklickt wird, diese Notiz durch Ausführen der Funktion <code>deleteItem()</code> löschen wird, die wir im nächsten Abschnitt betrachten werden.</li> <li>Am Ende des <code>if</code> Blocks verwenden wir die Methode <a href="/de/docs/Web/API/IDBCursor/continue"><code>IDBCursor.continue()</code></a>, um den Cursor zum nächsten Datensatz im Datenspeicher zu verschieben und den Inhalt des <code>if</code> Blocks erneut auszuführen. Wenn es einen weiteren Datensatz zu durchlaufen gibt, führt dies dazu, dass er in die Seite eingefügt wird, und dann wird <code>continue()</code> erneut ausgeführt und so weiter.</li> <li>Wenn keine weiteren Datensätze zur Iteration vorhanden sind, wird <code>cursor</code> <code>undefined</code> zurückgeben, und deshalb wird der <code>else</code> Block anstelle des <code>if</code> Blocks ausgeführt. Dieser Block prüft, ob Notizen in das <code><ul></code> eingefügt wurden – falls nicht, fügt er eine Nachricht ein, dass keine Notiz gespeichert wurde.</li> </ul></div></section><section aria-labelledby="eine_notiz_löschen"><h3 id="eine_notiz_löschen"><a href="#eine_notiz_löschen">Eine Notiz löschen</a></h3><div class="section-content"><p>Wie oben erwähnt, wenn der Lösch-Button einer Notiz gedrückt wird, wird die Notiz gelöscht. Dies geschieht durch die Funktion <code>deleteItem()</code>:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Define the deleteItem() function function deleteItem(e) { // retrieve the name of the task we want to delete. We need // to convert it to a number before trying to use it with IDB; IDB key // values are type-sensitive. const noteId = Number(e.target.parentNode.getAttribute("data-note-id")); // open a database transaction and delete the task, finding it using the id we retrieved above const transaction = db.transaction(["notes_os"], "readwrite"); const objectStore = transaction.objectStore("notes_os"); const deleteRequest = objectStore.delete(noteId); // report that the data item has been deleted transaction.addEventListener("complete", () => { // delete the parent of the button // which is the list item, so it is no longer displayed e.target.parentNode.parentNode.removeChild(e.target.parentNode); console.log(`Note ${noteId} deleted.`); // Again, if list item is empty, display a 'No notes stored' message if (!list.firstChild) { const listItem = document.createElement("li"); listItem.textContent = "No notes stored."; list.appendChild(listItem); } }); } </code></pre></div> <ul> <li>Der erste Teil davon könnte etwas Erklärung benötigen – wir rufen die ID des zu löschenden Datensatzes mit <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> ab – erinnern Sie sich, dass die ID des Datensatzes in einem <code>data-note-id</code> Attribut auf dem <code><li></code> gespeichert wurde, als es zuerst angezeigt wurde. Wir müssen das Attribut jedoch durch das globale eingebaute Objekt <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Number"><code>Number()</code></a> laufen lassen, da es vom Datentyp String ist und daher nicht von der Datenbank erkannt würde, die eine Zahl erwartet.</li> <li>Dann erhalten wir eine Referenz auf den Objektspeicher, indem wir das gleiche Muster verwenden, das wir zuvor gesehen haben, und verwenden die Methode <a href="/de/docs/Web/API/IDBObjectStore/delete"><code>IDBObjectStore.delete()</code></a>, um den Datensatz aus der Datenbank zu löschen, und übergeben ihm die ID.</li> <li>Wenn die Datenbanktransaktion abgeschlossen ist, löschen wir das <code><li></code> der Notiz aus dem DOM und führen erneut den Check durch, ob das <code><ul></code> nun leer ist und fügen eine entsprechende Notiz ein.</li> </ul> <p>Das war's! Ihr Beispiel sollte nun funktionieren.</p> <p>Wenn Sie damit Schwierigkeiten haben, zögern Sie nicht, <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/" class="external" target="_blank">es mit unserem Live-Beispiel zu vergleichen</a> (siehe auch den <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/index.js" class="external" target="_blank">Quellcode</a>).</p></div></section><section aria-labelledby="speichern_komplexer_daten_über_indexeddb"><h3 id="speichern_komplexer_daten_über_indexeddb"><a href="#speichern_komplexer_daten_über_indexeddb">Speichern komplexer Daten über IndexedDB</a></h3><div class="section-content"><p>Wie oben erwähnt, kann IndexedDB verwendet werden, um mehr als nur Textstrings zu speichern. Sie können so ziemlich alles speichern, was Sie möchten, einschließlich komplexer Objekte wie Video- oder Bildblobs. Und es ist nicht viel schwieriger zu erreichen als jede andere Art von Daten.</p> <p>Um zu demonstrieren, wie das geht, haben wir ein weiteres Beispiel namens <a href="https://github.com/mdn/learning-area/tree/main/javascript/apis/client-side-storage/indexeddb/video-store" class="external" target="_blank">IndexedDB-Video-Store</a> geschrieben (sehen Sie es <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/" class="external" target="_blank">auch live hier laufen</a>). Wenn Sie das Beispiel zum ersten Mal ausführen, werden alle Videos aus dem Netzwerk heruntergeladen, in einer IndexedDB-Datenbank gespeichert und dann die Videos innerhalb von <a href="/de/docs/Web/HTML/Element/video"><code><video></code></a>-Elementen in der Benutzeroberfläche angezeigt. Beim zweiten Mal wird geprüft, ob die Videos in der Datenbank vorhanden sind, und sie werden von dort geholt, bevor sie angezeigt werden – dies macht spätere Ladezeiten viel schneller und weniger bandbreitenhungrig.</p> <p>Lassen Sie uns die interessantesten Teile des Beispiels durchgehen. Wir werden nicht alles behandeln – Vieles davon ist ähnlich wie das vorherige Beispiel, und der Code ist gut kommentiert.</p> <ol> <li> <p>Für dieses Beispiel haben wir die Namen der abzurufenden Videos in einem Array von Objekten gespeichert:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const videos = [ { name: "crystal" }, { name: "elf" }, { name: "frog" }, { name: "monster" }, { name: "pig" }, { name: "rabbit" }, ]; </code></pre></div> </li> <li> <p>Zuerst, sobald die Datenbank erfolgreich geöffnet wurde, führen wir eine <code>init()</code> Funktion aus. Diese durchläuft die verschiedenen Videonamen und versucht, einen durch jeden Namen identifizierten Datensatz aus der <code>videos</code> Datenbank zu laden.</p> <p>Wenn jedes Video in der Datenbank gefunden wird (überprüft durch das Sehen, ob <code>request.result</code> zu <code>true</code> ausgewertet wird – wenn der Datensatz nicht vorhanden ist, wird er <code>undefined</code> sein), werden seine Videodateien (gespeichert als Blobs) und der Name des Videos direkt an die Funktion <code>displayVideo()</code> übergeben, um sie in der Benutzeroberfläche zu platzieren. Falls nicht, wird der Videoname an die Funktion <code>fetchVideoFromNetwork()</code> übergeben, um das Video aus dem Netzwerk zu holen.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>function init() { // Loop through the video names one by one for (const video of videos) { // Open transaction, get object store, and get() each video by name const objectStore = db.transaction("videos_os").objectStore("videos_os"); const request = objectStore.get(video.name); request.addEventListener("success", () => { // If the result exists in the database (is not undefined) if (request.result) { // Grab the videos from IDB and display them using displayVideo() console.log("taking videos from IDB"); displayVideo( request.result.mp4, request.result.webm, request.result.name, ); } else { // Fetch the videos from the network fetchVideoFromNetwork(video); } }); } } </code></pre></div> </li> <li> <p>Das folgende Snippet stammt aus dem Inneren von <code>fetchVideoFromNetwork()</code> – hier holen wir MP4- und WebM-Versionen des Videos mit zwei separaten <a href="/de/docs/Web/API/Window/fetch"><code>fetch()</code></a> Anfragen. Wir verwenden dann die Methode <a href="/de/docs/Web/API/Response/blob"><code>Response.blob()</code></a>, um den Körper jeder Antwort als Blob zu extrahieren, was uns eine Objektrepräsentation der Videos gibt, die später gespeichert und angezeigt werden kann.</p> <p>Wir haben hier jedoch ein Problem – diese beiden Anfragen sind asynchron, aber wir möchten versuchen, das Video nur dann anzuzeigen oder zu speichern, wenn beide Versprechen erfüllt sind. Glücklicherweise gibt es eine eingebaute Methode, die ein solches Problem handhabt – <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/all"><code>Promise.all()</code></a>. Diese nimmt ein Argument – Verweise auf alle einzelnen Versprechen, die Sie auf Erfüllung prüfen möchten, platziert in einem Array – und gibt ein Versprechen zurück, das erfüllt ist, wenn alle einzelnen Versprechen erfüllt sind.</p> <p>Im <code>then()</code> Handler für dieses Versprechen rufen wir die Funktion <code>displayVideo()</code> auf, genau wie zuvor, um die Videos in der Benutzeroberfläche anzuzeigen, dann rufen wir auch die Funktion <code>storeVideo()</code> auf, um diese Videos in der Datenbank zu speichern.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Fetch the MP4 and WebM versions of the video using the fetch() function, // then expose their response bodies as blobs const mp4Blob = fetch(`videos/${video.name}.mp4`).then((response) => response.blob(), ); const webmBlob = fetch(`videos/${video.name}.webm`).then((response) => response.blob(), ); // Only run the next code when both promises have fulfilled Promise.all([mp4Blob, webmBlob]).then((values) => { // display the video fetched from the network with displayVideo() displayVideo(values[0], values[1], video.name); // store it in the IDB using storeVideo() storeVideo(values[0], values[1], video.name); }); </code></pre></div> </li> <li> <p>Schauen wir uns zuerst <code>storeVideo()</code> an. Dies ist dem Muster, das Sie im vorherigen Beispiel für das Hinzufügen von Daten zur Datenbank gesehen haben, sehr ähnlich – wir öffnen eine <code>readwrite</code> Transaktion und erhalten eine Referenz auf unseren <code>videos_os</code> Objektspeicher, erstellen ein Objekt, das den zur Datenbank hinzuzufügenden Datensatz repräsentiert, und fügen es dann mit <a href="/de/docs/Web/API/IDBObjectStore/add"><code>IDBObjectStore.add()</code></a> hinzu.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Define the storeVideo() function function storeVideo(mp4, webm, name) { // Open transaction, get object store; make it a readwrite so we can write to the IDB const objectStore = db .transaction(["videos_os"], "readwrite") .objectStore("videos_os"); // Add the record to the IDB using add() const request = objectStore.add({ mp4, webm, name }); request.addEventListener("success", () => console.log("Record addition attempt finished"), ); request.addEventListener("error", () => console.error(request.error)); } </code></pre></div> </li> <li> <p>Schließlich haben wir <code>displayVideo()</code>, das die benötigten DOM-Elemente erstellt, um das Video in der Benutzeroberfläche einzufügen, und sie dann der Seite hinzufügt. Die interessantesten Teile davon sind die unten gezeigten – um tatsächlich unsere Videoblobs in einem <code><video></code>-Element anzuzeigen, müssen wir Objekt-URLs (interne URLs, die auf die in den Speicher geladenen Videoblobs zeigen) mit der Methode <a href="/de/docs/Web/API/URL/createObjectURL_static"><code>URL.createObjectURL()</code></a> erstellen. Sobald das erledigt ist, können wir die Objekt-URLs als Werte der <code>src</code> Attribute unserer <a href="/de/docs/Web/HTML/Element/source"><code><source></code></a> Elemente setzen, und es funktioniert einwandfrei.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Define the displayVideo() function function displayVideo(mp4Blob, webmBlob, title) { // Create object URLs out of the blobs const mp4URL = URL.createObjectURL(mp4Blob); const webmURL = URL.createObjectURL(webmBlob); // Create DOM elements to embed video in the page const article = document.createElement("article"); const h2 = document.createElement("h2"); h2.textContent = title; const video = document.createElement("video"); video.controls = true; const source1 = document.createElement("source"); source1.src = mp4URL; source1.type = "video/mp4"; const source2 = document.createElement("source"); source2.src = webmURL; source2.type = "video/webm"; // Embed DOM elements into page section.appendChild(article); article.appendChild(h2); article.appendChild(video); video.appendChild(source1); video.appendChild(source2); } </code></pre></div> </li> </ol></div></section><section aria-labelledby="offline-asset-speicherung"><h2 id="offline-asset-speicherung"><a href="#offline-asset-speicherung">Offline-Asset-Speicherung</a></h2><div class="section-content"><p>Das obige Beispiel zeigt bereits, wie man eine App erstellt, die große Assets in einer IndexedDB-Datenbank speichert und das Herunterladen dieser mehr als einmal vermeiden kann. Dies ist bereits eine große Verbesserung der Nutzererfahrung, aber es fehlt noch etwas – die Haupt-HTML-, CSS- und JavaScript-Dateien müssen immer noch jedes Mal heruntergeladen werden, wenn auf die Seite zugegriffen wird, was bedeutet, dass sie bei fehlender Netzwerkverbindung nicht funktionieren würde.</p> <p><img src="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage/ff-offline.png" alt="Firefox Offline-Bildschirm mit einer Illustration eines Cartoon-Charakters auf der linken Seite, der einen zwei-Pin-Stecker in seiner rechten Hand und eine zwei-Pin-Buchse in seiner linken Hand hält. Auf der rechten Seite gibt es eine Offline-Modus-Meldung und einen Button mit der Bezeichnung 'Try again'." width="765" height="307" loading="lazy"></p> <p>An dieser Stelle kommen <a href="/de/docs/Web/API/Service_Worker_API">Service Worker</a> und die eng verwandte <a href="/de/docs/Web/API/Cache">Cache API</a> ins Spiel.</p> <p>Ein Service Worker ist eine JavaScript-Datei, die gegen einen bestimmten Ursprung (Website oder Teil einer Website an einer bestimmten Domäne) registriert wird, wenn darauf von einem Browser zugegriffen wird. Wenn sie registriert ist, kann sie die Seiten des Ursprungs steuern, indem sie zwischen einer geladenen Seite und dem Netzwerk sitzt und alle Netzwerk-Anfragen abfängt, die auf diesen Ursprung gerichtet sind.</p> <p>Wenn sie eine Anfrage abfängt, kann sie mit der Anfrage alles tun, was Sie möchten (siehe <a href="/de/docs/Web/API/Service_Worker_API#other_use_case_ideas">Use-Case-Ideen</a>), aber das klassische Beispiel ist das Speichern der Netzwerkantworten offline und das Bereitstellen dieser als Antwort auf eine Anfrage statt der Antworten aus dem Netzwerk. Im Effekt ermöglicht es Ihnen, eine Website vollständig offline zu machen.</p> <p>Die Cache API ist ein weiteres client-seitiges Speichermechanismus mit einem kleinen Unterschied – es ist dafür ausgelegt, HTTP-Antworten zu speichern und funktioniert daher sehr gut mit Service Workern.</p></div></section><section aria-labelledby="ein_service-worker-beispiel"><h3 id="ein_service-worker-beispiel"><a href="#ein_service-worker-beispiel">Ein Service-Worker-Beispiel</a></h3><div class="section-content"><p>Schauen wir uns ein Beispiel an, um Ihnen eine Vorstellung davon zu geben, wie könnte dies aussehen. Wir haben eine andere Version des zuvor in Abschnitt betrachteten Video-Store-Beispiels erstellt – dies funktioniert identisch, außer dass es auch die HTML-, CSS- und JavaScript-Dateien in der Cache API über einen Service Worker speichert, was das Beispiel offline funktionsfähig macht!</p> <p>Sehen Sie <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/" class="external" target="_blank">IndexedDB-Video-Store mit Service Worker live laufen</a>, und sehen Sie auch <a href="https://github.com/mdn/learning-area/tree/main/javascript/apis/client-side-storage/cache-sw/video-store-offline" class="external" target="_blank">den Quellcode</a>.</p> <h4 id="registrierung_des_service_workers">Registrierung des Service Workers</h4> <p>Das erste, was es zu beachten gibt, ist dass es einen zusätzlichen Codeabschnitt in der Haupt-JavaScript-Datei gibt (siehe <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js" class="external" target="_blank">index.js</a>). Zuerst machen wir einen Feature-Erkennungstest, um zu sehen, ob das <code>serviceWorker</code> Mitglied im <a href="/de/docs/Web/API/Navigator"><code>Navigator</code></a> Objekt verfügbar ist. Wenn dies <code>true</code> zurückgibt, wissen wir, dass mindestens die Grundlagen der Service Worker unterstützt werden. Hier verwenden wir die Methode <a href="/de/docs/Web/API/ServiceWorkerContainer/register"><code>ServiceWorkerContainer.register()</code></a>, um einen im <code>sw.js</code> Datei enthaltenen Service Worker gegen den Ursprung, an dem er sich befindet, zu registrieren, damit er Seiten im gleichen Verzeichnis wie er oder Unterverzeichnisse steuern kann. Wenn das Versprechen erfüllt ist, wird der Service Worker als registriert angesehen.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>// Register service worker to control making site work offline if ("serviceWorker" in navigator) { navigator.serviceWorker .register( "/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js", ) .then(() => console.log("Service Worker Registered")); } </code></pre></div> <div class="notecard note"> <p><strong>Hinweis:</strong> Der angegebene Pfad zur <code>sw.js</code> Datei ist relativ zum Standort des Ursprungs, nicht die JavaScript-Datei, die den Code enthält. Der Service Worker befindet sich an <code>https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. Der Ursprung ist <code>https://mdn.github.io</code>, und deshalb muss der angegebene Pfad <code>/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code> sein. Wenn Sie dieses Beispiel auf Ihrem eigenen Server hosten möchten, müssten Sie dies entsprechend ändern. Dies ist eher verwirrend, aber es muss aus Sicherheitsgründen so funktionieren.</p> </div> <h4 id="installation_des_service_workers">Installation des Service Workers</h4> <p>Das nächste Mal, wenn auf eine Seite unter der Kontrolle des Service Workers zugegriffen wird (z.B. wenn das Beispiel neu geladen wird), wird der Service Worker gegen diese Seite installiert, was bedeutet, dass er beginnt, sie zu steuern. Wenn dies geschieht, wird ein <code>install</code> Ereignis gegen den Service Worker ausgelöst; Sie können Code innerhalb des Service Worker selbst schreiben, der auf die Installation reagieren wird.</p> <p>Schauen wir uns ein Beispiel an, in der <a href="https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js" class="external" target="_blank">sw.js</a> Datei (dem Service Worker). Sie werden sehen, dass der Installations-Listener gegen <code>self</code> registriert wird. Dieses <code>self</code> Schlüsselwort ist eine Möglichkeit, auf den globalen Bereich des Service Workers von innerhalb der Service-Worker-Datei zu verweisen.</p> <p>Innerhalb des <code>install</code> Handlers verwenden wir die Methode <a href="/de/docs/Web/API/ExtendableEvent/waitUntil"><code>ExtendableEvent.waitUntil()</code></a>, die auf dem Ereignis-Objekt verfügbar ist, um anzugeben, dass der Browser die Installation des Service Workers nicht abschließen sollte, bis das Versprechen innerhalb erfolgreich erfüllt wurde.</p> <p>Hier sehen wir die Cache API in Aktion. Wir verwenden die Methode <a href="/de/docs/Web/API/CacheStorage/open"><code>CacheStorage.open()</code></a>, um ein neues Cache-Objekt zu öffnen, in dem Antworten gespeichert werden können (ähnlich wie ein IndexedDB-Objektspeicher). Dieses Versprechen erfüllt sich mit einem <a href="/de/docs/Web/API/Cache"><code>Cache</code></a> Objekt, das den <code>video-store</code> Cache repräsentiert. Wir verwenden dann die Methode <a href="/de/docs/Web/API/Cache/addAll"><code>Cache.addAll()</code></a>, um eine Reihe von Assets abzurufen und deren Antworten zum Cache hinzuzufügen.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>self.addEventListener("install", (e) => { e.waitUntil( caches .open("video-store") .then((cache) => cache.addAll([ "/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/", "/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html", "/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js", "/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css", ]), ), ); }); </code></pre></div> <p>Das war's vorerst, Installation fertig.</p> <h4 id="reagieren_auf_weitere_anfragen">Reagieren auf weitere Anfragen</h4> <p>Mit dem Service Worker registriert und gegen unsere HTML-Seite installiert und den entsprechenden Assets alle zu unserem Cache hinzugefügt, sind wir fast bereit zu gehen. Es gibt nur noch eine Sache zu tun: etwas Code schreiben, um auf weitere Netzwerk-Anfragen zu reagieren.</p> <p>Das ist es, was der zweite Code in <code>sw.js</code> tut. Wir fügen einen weiteren Listener zum globalen Bereich des Service Workers hinzu, der die Handler-Funktion ausführt, wenn das <code>fetch</code> Ereignis ausgelöst wird. Dies geschieht, wenn der Browser eine Anfrage für ein Asset in dem Verzeichnis stellt, gegen das der Service Worker registriert ist.</p> <p>Innerhalb des Handlers loggen wir zuerst die URL des angeforderten Assets. Dann geben wir eine benutzerdefinierte Antwort auf die Anfrage, mit der Methode <a href="/de/docs/Web/API/FetchEvent/respondWith"><code>FetchEvent.respondWith()</code></a>.</p> <p>Innerhalb dieses Blocks überprüfen wir, ob eine passende Anfrage (das heißt, die URL entspricht) in einem Cache gefunden werden kann, indem wir <a href="/de/docs/Web/API/CacheStorage/match"><code>CacheStorage.match()</code></a> verwenden. Dieses Versprechen erfüllt sich mit der passenden Antwort, wenn ein Treffer gefunden wird, oder <code>undefined</code>, wenn nicht.</p> <p>Wenn ein Treffer gefunden wird, geben wir ihn als benutzerdefinierte Antwort zurück. Andernfalls rufen wir die Antwort mit einem <a href="/de/docs/Web/API/Window/fetch">fetch()</a> aus dem Netzwerk ab und geben diese stattdessen zurück.</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>self.addEventListener("fetch", (e) => { console.log(e.request.url); e.respondWith( caches.match(e.request).then((response) => response || fetch(e.request)), ); }); </code></pre></div> <p>Und das war's für unseren Service Worker. Es gibt noch viel mehr, was Sie mit ihnen tun können – für eine ausführlichere Betrachtung, siehe das <a href="https://github.com/mdn/serviceworker-cookbook" class="external" target="_blank">Service Worker Cookbook</a>. Vielen Dank an Paul Kinlan für seinen Artikel <a href="https://developers.google.com/codelabs/pwa-training/pwa03--going-offline#0" class="external" target="_blank">Adding a Service Worker and Offline into your Web App</a>, der dieses Beispiel inspiriert hat.</p> <h4 id="testen_des_beispiels_im_offline-modus">Testen des Beispiels im Offline-Modus</h4> <p>Um unser <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/" class="external" target="_blank">Service Worker Beispiel</a> zu testen, müssen Sie es ein paar Mal laden, um sicherzustellen, dass es installiert ist. Sobald dies geschehen ist, können Sie:</p> <ul> <li>Versuchen Sie, Ihr Netzwerk auszustecken / Ihre Wi-Fi auszuschalten.</li> <li>Wählen Sie <em>Datei > Offline arbeiten</em> wenn Sie Firefox verwenden.</li> <li>Gehen Sie zu den Devtools, dann wählen Sie <em>Anwendung > Service Worker</em>, dann markieren Sie das <em>Offline</em> Kontrollkästchen, wenn Sie Chrome verwenden.</li> </ul> <p>Wenn Sie Ihre Beispielseite erneut laden, sollten Sie sehen, dass sie weiterhin einwandfrei lädt. Alles ist offline gespeichert – die Seite-Assets in einem Cache und die Videos in einer IndexedDB-Datenbank.</p></div></section><section aria-labelledby="zusammenfassung"><h2 id="zusammenfassung"><a href="#zusammenfassung">Zusammenfassung</a></h2><div class="section-content"><p>Das war's für den Moment. Wir hoffen, dass unser Überblick über client-seitige Speichertechnologien für Sie nützlich war.</p></div></section><section aria-labelledby="siehe_auch"><h2 id="siehe_auch"><a href="#siehe_auch">Siehe auch</a></h2><div class="section-content"><ul> <li><a href="/de/docs/Web/API/Web_Storage_API">Web storage API</a></li> <li><a href="/de/docs/Web/API/IndexedDB_API">IndexedDB API</a></li> <li><a href="/de/docs/Web/HTTP/Cookies">Cookies</a></li> <li><a href="/de/docs/Web/API/Service_Worker_API">Service worker API</a></li> </ul> <ul class="prev-next"><li><a class="button secondary" href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics"><span class="button-wrap"> Zurück </span></a></li><li><a class="button secondary" href="/de/docs/Learn_web_development/Extensions/Client-side_APIs"><span class="button-wrap"> Übersicht: Client-seitige Web-APIs</span></a></li><li><a class="button secondary" href="/de/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs"><span class="button-wrap"> Weiter </span></a></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>MDN-Feedback-Box</h2><fieldset class="feedback"><label>War diese Übersetzung hilfreich?</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>Ja</span></button><button type="button" class="button primary has-icon no"><span class="button-wrap"><span class="icon icon-thumbs-down "></span>Nein</span></button></div></fieldset><p class="last-modified-date">Diese Seite wurde automatisch aus dem Englischen übersetzt.</p><div id="on-github" class="on-github"><a href="https://github.com/mdn/translated-content-de/blob/main/files/de/learn_web_development/extensions/client-side_apis/client-side_storage/index.md?plain=1" title="Folder: de/learn_web_development/extensions/client-side_apis/client-side_storage (Opens in a new tab)" target="_blank" rel="noopener noreferrer">Übersetzung auf GitHub anzeigen</a> <!-- -->•<!-- --> <a href="https://github.com/mdn/translated-content-de/issues/new?template=page-report-de.yml&mdn-url=https%3A%2F%2Fdeveloper.mozilla.org%2Fde%2Fdocs%2FLearn_web_development%2FExtensions%2FClient-side_APIs%2FClient-side_storage&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+%60de%2Flearn_web_development%2Fextensions%2Fclient-side_apis%2Fclient-side_storage%60%0A*+MDN+URL%3A+https%3A%2F%2Fdeveloper.mozilla.org%2Fde%2Fdocs%2FLearn_web_development%2FExtensions%2FClient-side_APIs%2FClient-side_storage%0A*+GitHub+URL%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Ftranslated-content-de%2Fblob%2Fmain%2Ffiles%2Fde%2Flearn_web_development%2Fextensions%2Fclient-side_apis%2Fclient-side_storage%2Findex.md%0A*+Last+commit%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Ftranslated-content-de%2Fcommit%2F452fe502cfb4c9a91c346af17370ecfb6a8bd17e%0A*+Document+last+modified%3A+2025-02-17T00%3A20%3A27.000Z%0A%0A%3C%2Fdetails%3E" title="This will take you to GitHub to file a new issue." target="_blank" rel="noopener noreferrer">Fehler mit dieser Übersetzung melden</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://mastodon.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="/de/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="/de/docs/Web">Web Technologies</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/de/docs/Learn">Learn Web Development</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/de/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 xmlns="http://www.w3.org/2000/svg" width="137" height="32" fill="none" viewBox="0 0 267.431 62.607"><path fill="currentColor" d="m13.913 23.056 5.33 25.356h2.195l5.33-25.356h14.267v38.976h-7.578V29.694h-2.194l-7.264 32.337h-7.343L9.418 29.694H7.223v32.337H-.354V23.056Zm47.137 9.123c9.12 0 14.423 5.385 14.423 15.214s-5.33 15.214-14.423 15.214c-9.12 0-14.423-5.385-14.423-15.214 0-9.855 5.304-15.214 14.423-15.214m0 24.363c4.285 0 6.428-2.196 6.428-7.032v-4.287c0-4.836-2.143-7.032-6.428-7.032s-6.428 2.196-6.428 7.032v4.287c0 4.836 2.143 7.032 6.428 7.032m18.473-.157 15.47-18.01h-15.26v-5.647h24.352v5.646L88.616 56.385h15.704v5.646H79.523Zm29.318-23.657h11.183V62.03h-7.578V38.375h-3.632v-5.646zm3.605-9.672h7.578v5.646h-7.578zm13.17 0h11.21v38.976h-7.578v-33.33h-3.632zm16.801 0H153.6v38.976h-7.577v-33.33h-3.632v-5.646zm29.03 9.123c4.442 0 7.394 2.143 8.231 5.881h2.194v-5.332h9.276v5.646h-3.632v18.011h3.632v5.646h-4.442c-3.135 0-4.834-1.699-4.834-4.836V56.7h-2.194c-.81 3.738-3.789 5.881-8.23 5.881-6.978 0-11.916-5.829-11.916-15.214 0-9.384 4.938-15.187 11.915-15.187m2.3 24.363c4.284 0 6.192-2.196 6.192-7.032v-4.287c0-4.836-1.908-7.032-6.193-7.032-4.18 0-6.193 2.196-6.193 7.032v4.287c0 4.836 2.012 7.032 6.193 7.032m48.34 5.489h-7.577V0h7.577zm6.585-29.643h32.165v-2.196l-21.295-7.634v-6.143l21.295-7.633V6.588h-25.345V0h32.165v12.522l-17.35 5.881V20.6l17.35 5.882v12.521h-38.985zm0-25.801h6.794v6.796h-6.794z"></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–<!-- -->2025<!-- --> by individual mozilla.org contributors. Content available under<!-- --> <a href="/de/docs/MDN/Writing_guidelines/Attrib_copyright_license">a Creative Commons license</a>.</p></div></div></footer></div><script type="application/json" id="hydration">{"url":"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage","doc":{"body":[{"type":"prose","value":{"id":null,"title":null,"isH3":false,"content":"<ul class=\"prev-next\"><li><a class=\"button secondary\" href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics\"><span class=\"button-wrap\"> Zurück </span></a></li><li><a class=\"button secondary\" href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs\"><span class=\"button-wrap\"> Übersicht: Client-seitige Web-APIs</span></a></li><li><a class=\"button secondary\" href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs\"><span class=\"button-wrap\"> Weiter </span></a></li></ul>\n<p>Moderne Webbrowser unterstützen eine Vielzahl von Möglichkeiten, wie Websites Daten auf dem Rechner des Nutzers speichern und bei Bedarf abrufen können – mit der Erlaubnis des Nutzers. Dies ermöglicht Ihnen, Daten für die langfristige Speicherung zu speichern, Seiten oder Dokumente für die Offline-Nutzung zu sichern, nutzerspezifische Einstellungen für Ihre Website zu behalten und mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Techniken.</p>\n<figure class=\"table-container\"><table>\n <tbody>\n <tr>\n <th scope=\"row\">Voraussetzungen:</th>\n <td>\n Vertrautheit mit <a href=\"/de/docs/Learn_web_development/Core/Structuring_content\">HTML</a>, <a href=\"/de/docs/Learn_web_development/Core/Styling_basics\">CSS</a> und <a href=\"/de/docs/Learn_web_development/Core/Scripting\">JavaScript</a>, insbesondere den <a href=\"/de/docs/Learn_web_development/Core/Scripting/Object_basics\">JavaScript-Objekt-Grundlagen</a> und der grundlegenden API-Abdeckung wie <a href=\"/de/docs/Learn_web_development/Core/Scripting/DOM_scripting\">DOM-Scripting</a> und <a href=\"/de/docs/Learn_web_development/Core/Scripting/Network_requests\">Netzwerkanfragen</a>.\n </td>\n </tr>\n <tr>\n <th scope=\"row\">Lernziele:</th>\n <td>\n <ul>\n <li>Die Konzepte des client-seitigen Speichers und welche Schlüsseltechnologien dies ermöglichen – Web Storage API, Cookies, Cache API und die IndexedDB API.</li>\n <li>Wichtige Anwendungsfälle – Zustand zwischen Neuladungen aufrechterhalten, Login- und Nutzerpersonalisierungsdaten beibehalten und lokale/offline Arbeit.</li>\n <li>Web Storage für einfache Schlüssel-Wert-Paar-Speicherungen verwenden, gesteuert durch JavaScript.</li>\n <li>Die Verwendung von IndexedDB zum Speichern komplexerer, strukturierter Daten.</li>\n <li>Die Verwendung der Cache API und Service Worker für Offline-Anwendungsfälle.</li>\n </ul>\n </td>\n </tr>\n </tbody>\n</table></figure>"}},{"type":"prose","value":{"id":"client-seitiger_speicher","title":"Client-seitiger Speicher?","isH3":false,"content":"<p>An anderer Stelle im MDN-Lernbereich haben wir über den Unterschied zwischen <a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview#static_sites\">statischen Websites</a> und <a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview#dynamic_sites\">dynamischen Websites</a> gesprochen. Die meisten großen modernen Websites sind dynamisch – sie speichern Daten auf dem Server mithilfe einer Datenbank (serverseitiger Speicher) und führen <a href=\"/de/docs/Learn_web_development/Extensions/Server-side\">serverseitigen</a> Code aus, um die benötigten Daten abzurufen, sie in statische Seitentemplates einzufügen und das resultierende HTML dem Client zur Anzeige im Browser des Nutzers bereitzustellen.</p>\n<p>Client-seitiger Speicher funktioniert nach ähnlichen Prinzipien, hat jedoch unterschiedliche Anwendungsfälle. Er besteht aus JavaScript-APIs, die Ihnen erlauben, Daten auf dem Client (d.h. auf dem Rechner des Nutzers) zu speichern und bei Bedarf abzurufen. Dies hat viele verschiedene Anwendungen, wie:</p>\n<ul>\n<li>Personalisierung von Seiteneinstellungen (z. B. Anzeige der Auswahl eines Nutzers zu benutzerdefinierten Widgets, Farbschema oder Schriftgröße).</li>\n<li>Beibehalten früherer Website-Aktivitäten (z. B. Speichern der Inhalte eines Warenkorbs aus einer früheren Sitzung, Erinnern daran, ob ein Nutzer zuvor eingeloggt war).</li>\n<li>Lokales Speichern von Daten und Assets, damit eine Seite schneller (und möglicherweise kostengünstiger) heruntergeladen werden kann oder ohne Netzwerkverbindung nutzbar ist.</li>\n<li>Lokales Speichern von von Webanwendungen generierten Dokumenten zur Offline-Nutzung</li>\n</ul>\n<p>Häufig werden client-seitiger und server-seitiger Speicher zusammen verwendet. Zum Beispiel könnten Sie eine Reihe von Musikdateien herunterladen (vielleicht genutzt von einem Webspiel oder einer Musikplayer-Anwendung), sie in einer client-seitigen Datenbank speichern und bei Bedarf abspielen. Die Nutzer müssten die Musikdateien nur einmal herunterladen – bei späteren Besuchen würden sie stattdessen aus der Datenbank abgerufen.</p>\n<div class=\"notecard note\">\n<p><strong>Hinweis:</strong>\nEs gibt Einschränkungen hinsichtlich der Menge an Daten, die Sie mit client-seitigen Speicher-APIs speichern können (möglicherweise sowohl pro individueller API als auch kumulativ); das genaue Limit variiert je nach Browser und möglicherweise basierend auf den Einstellungen des Nutzers. Weitere Informationen finden Sie unter <a href=\"/de/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria\">Speicherquoten und Auslöschkriterien für den Browser</a>.</p>\n</div>"}},{"type":"prose","value":{"id":"altmodisch_cookies","title":"Altmodisch: Cookies","isH3":true,"content":"<p>Das Konzept des client-seitigen Speichers gibt es schon lange. Seit den frühen Tagen des Webs haben Websites <a href=\"/de/docs/Web/HTTP/Cookies\">Cookies</a> genutzt, um Informationen zur Personalisierung der Nutzererfahrung auf Websites zu speichern. Sie sind die älteste Form des client-seitigen Speichers, der im Web weit verbreitet ist.</p>\n<p>Heutzutage gibt es einfachere Mechanismen zur Speicherung client-seitiger Daten, daher werden wir Ihnen in diesem Artikel nicht beibringen, wie man Cookies verwendet. Dies bedeutet jedoch nicht, dass Cookies im modernen Web völlig nutzlos sind – sie werden weiterhin häufig verwendet, um Daten im Zusammenhang mit Nutzerpersonalisierung und -zustand zu speichern, z. B. Sitzungs-IDs und Zugangs-Token. Weitere Informationen zu Cookies finden Sie in unserem Artikel <a href=\"/de/docs/Web/HTTP/Cookies\">Verwendung von HTTP-Cookies</a>.</p>"}},{"type":"prose","value":{"id":"modern_web_storage_und_indexeddb","title":"Modern: Web Storage und IndexedDB","isH3":true,"content":"<p>Die oben erwähnten \"einfacheren\" Funktionen sind wie folgt:</p>\n<ul>\n<li>Die <a href=\"/de/docs/Web/API/Web_Storage_API\">Web Storage API</a> bietet einen Mechanismus zum Speichern und Abrufen kleinerer Datenitems, die aus einem Namen und einem entsprechenden Wert bestehen. Dies ist nützlich, wenn Sie nur einige einfache Daten speichern müssen, wie den Namen des Nutzers, ob er eingeloggt ist, welche Farbe für den Hintergrund des Bildschirms verwendet werden soll, usw.</li>\n<li>Die <a href=\"/de/docs/Web/API/IndexedDB_API\">IndexedDB API</a> stellt dem Browser ein vollständiges Datenbanksystem zur Verfügung, um komplexe Daten zu speichern. Dies kann verwendet werden für Dinge von vollständigen Datenbeständen von Kunden bis hin zu komplexen Datentypen wie Audio- oder Videodateien.</li>\n</ul>\n<p>Sie werden mehr über diese APIs im Folgenden lernen.</p>"}},{"type":"prose","value":{"id":"die_cache_api","title":"Die Cache API","isH3":true,"content":"<p>Die <a href=\"/de/docs/Web/API/Cache\"><code>Cache</code></a> API ist dafür ausgelegt, HTTP-Antworten auf bestimmte Anfragen zu speichern, und ist sehr nützlich für Dinge wie das Speichern von Website-Assets offline, damit die Seite auch ohne Netzwerkverbindung genutzt werden kann. Die Cache API wird normalerweise in Kombination mit der <a href=\"/de/docs/Web/API/Service_Worker_API\">Service Worker API</a> verwendet, obwohl das nicht zwingend notwendig ist.</p>\n<p>Die Verwendung von Cache und Service Workern ist ein fortgeschrittenes Thema, und wir werden es in diesem Artikel nicht im Detail behandeln, obwohl wir ein Beispiel im Abschnitt <a href=\"#offline-asset-speicherung\">Offline-Asset-Speicherung</a> weiter unten zeigen werden.</p>"}},{"type":"prose","value":{"id":"speichern_einfacher_daten_–_web_storage","title":"Speichern einfacher Daten – Web Storage","isH3":false,"content":"<p>Die <a href=\"/de/docs/Web/API/Web_Storage_API\">Web Storage API</a> ist sehr einfach zu verwenden – Sie speichern einfache Name/Wert-Paare von Daten (beschränkt auf Strings, Zahlen usw.) und rufen diese Werte bei Bedarf ab.</p>"}},{"type":"prose","value":{"id":"grundlegende_syntax","title":"Grundlegende Syntax","isH3":true,"content":"<p>Lassen Sie uns Ihnen zeigen, wie:</p>\n<ol>\n<li>\n<p>Besuchen Sie zunächst unser <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html\" class=\"external\" target=\"_blank\">leeres Web-Storage-Template</a> auf GitHub (öffnen Sie dies in einem neuen Tab).</p>\n</li>\n<li>\n<p>Öffnen Sie die JavaScript-Konsole der Entwicklerwerkzeuge Ihres Browsers.</p>\n</li>\n<li>\n<p>Alle Daten Ihres Webspeichers sind in zwei objektähnlichen Strukturen im Browser enthalten: <a href=\"/de/docs/Web/API/Window/sessionStorage\"><code>sessionStorage</code></a> und <a href=\"/de/docs/Web/API/Window/localStorage\"><code>localStorage</code></a>. Das erste speichert Daten für die Dauer, in der der Browser geöffnet ist (die Daten gehen verloren, wenn der Browser geschlossen wird), und das zweite speichert Daten auch noch nach dem Schließen und erneuten Öffnen des Browsers. Wir werden in diesem Artikel das zweite verwenden, da es im Allgemeinen nützlicher ist.</p>\n<p>Die Methode <a href=\"/de/docs/Web/API/Storage/setItem\"><code>Storage.setItem()</code></a> ermöglicht Ihnen, ein Datenitem in den Speicher zu speichern – sie benötigt zwei Parameter: den Namen des Items und seinen Wert. Versuchen Sie, dies in Ihre JavaScript-Konsole einzugeben (Ändern Sie den Wert in Ihren eigenen Namen, wenn Sie möchten!):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>localStorage.setItem(\"name\", \"Chris\");\n</code></pre></div>\n</li>\n<li>\n<p>Die Methode <a href=\"/de/docs/Web/API/Storage/getItem\"><code>Storage.getItem()</code></a> benötigt einen Parameter – den Namen eines Datenitems, das Sie abrufen möchten – und gibt den Wert des Items zurück. Geben Sie nun diese Zeilen in Ihre JavaScript-Konsole ein:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>let myName = localStorage.getItem(\"name\");\nmyName;\n</code></pre></div>\n<p>Beim Eingeben der zweiten Zeile sollten Sie sehen, dass die Variable <code>myName</code> nun den Wert des <code>name</code> Datenitems enthält.</p>\n</li>\n<li>\n<p>Die Methode <a href=\"/de/docs/Web/API/Storage/removeItem\"><code>Storage.removeItem()</code></a> benötigt einen Parameter – den Namen eines Datenitems, das Sie entfernen möchten – und entfernt dieses Item aus dem Webspeicher. Geben Sie die folgenden Zeilen in Ihre JavaScript-Konsole ein:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>localStorage.removeItem(\"name\");\nmyName = localStorage.getItem(\"name\");\nmyName;\n</code></pre></div>\n<p>Die dritte Zeile sollte nun <code>null</code> zurückgeben – das <code>name</code> Item existiert nicht mehr im Webspeicher.</p>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"die_daten_bleiben_bestehen!","title":"Die Daten bleiben bestehen!","isH3":true,"content":"<p>Ein wesentliches Merkmal des Webspeichers ist, dass die Daten zwischen Seitenladevorgängen bestehen bleiben (und sogar nach dem Herunterfahren des Browsers, im Fall von <code>localStorage</code>). Lassen Sie uns dies in Aktion sehen.</p>\n<ol>\n<li>\n<p>Öffnen Sie unser leeres Web-Storage-Template erneut, diesmal jedoch in einem anderen Browser als dem, in dem Sie dieses Tutorial geöffnet haben! Dies macht es einfacher, damit umzugehen.</p>\n</li>\n<li>\n<p>Geben Sie diese Zeilen in die JavaScript-Konsole des Browsers ein:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>localStorage.setItem(\"name\", \"Chris\");\nlet myName = localStorage.getItem(\"name\");\nmyName;\n</code></pre></div>\n<p>Sie sollten das zurückgegebene <code>name</code> Item sehen.</p>\n</li>\n<li>\n<p>Schließen Sie nun den Browser und öffnen Sie ihn wieder.</p>\n</li>\n<li>\n<p>Geben Sie die folgenden Zeilen erneut ein:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>let myName = localStorage.getItem(\"name\");\nmyName;\n</code></pre></div>\n<p>Sie sollten sehen, dass der Wert immer noch verfügbar ist, obwohl der Browser geschlossen und dann wieder geöffnet wurde.</p>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"separater_speicher_für_jede_domäne","title":"Separater Speicher für jede Domäne","isH3":true,"content":"<p>Es gibt einen separaten Datenspeicher für jede Domäne (jede separate Webadresse, die im Browser geladen wird). Sie werden sehen, dass, wenn Sie zwei Websites laden (sagen wir google.com und amazon.com) und versuchen, ein Item auf einer Website zu speichern, es für die andere Website nicht verfügbar ist.</p>\n<p>Das macht Sinn – Sie können sich die Sicherheitsprobleme vorstellen, die auftreten würden, wenn Websites die Daten anderer Websites sehen könnten!</p>"}},{"type":"prose","value":{"id":"ein_umfangreicheres_beispiel","title":"Ein umfangreicheres Beispiel","isH3":true,"content":"<p>Lassen Sie uns dieses neue Wissen anwenden, indem wir ein funktionierendes Beispiel schreiben, um Ihnen eine Vorstellung davon zu geben, wie Webspeicher verwendet werden kann. Unser Beispiel ermöglicht es Ihnen, einen Namen einzugeben, nach dem die Seite aktualisiert wird, um Ihnen eine personalisierte Begrüßung zu geben. Dieser Zustand bleibt auch bei Seiten-/Browserneuladungen bestehen, da der Name im Webspeicher gespeichert wird.</p>\n<p>Sie finden das Beispiel-HTML unter <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/web-storage/personal-greeting.html\" class=\"external\" target=\"_blank\">personal-greeting.html</a> – es enthält eine Website mit einer Kopfzeile, einem Inhalt und einer Fußzeile sowie ein Formular zur Eingabe Ihres Namens.</p>\n<p><img src=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage/web-storage-demo.png\" alt=\"Ein Screenshot einer Website, die Abschnitte für einen Header, Inhalt und eine Fußzeile hat. Der Header hat einen Begrüßungstext auf der linken Seite und einen Button mit der Bezeichnung 'vergessen' auf der rechten Seite. Der Inhalt hat eine Überschrift gefolgt von zwei Absätzen mit Blindtext. Der Footer liest 'Copyright nobody. Use the code as you like'.\" width=\"1024\" height=\"550\" loading=\"lazy\"></p>\n<p>Lassen Sie uns das Beispiel aufbauen, damit Sie verstehen, wie es funktioniert.</p>\n<ol>\n<li>\n<p>Erstellen Sie zuerst eine lokale Kopie unserer <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/web-storage/personal-greeting.html\" class=\"external\" target=\"_blank\">personal-greeting.html</a> Datei in einem neuen Verzeichnis auf Ihrem Computer.</p>\n</li>\n<li>\n<p>Beachten Sie als Nächstes, wie unser HTML auf eine JavaScript-Datei namens <code>index.js</code> verweist, mit einer Zeile wie <code><script src=\"index.js\" defer></script></code>. Diese müssen wir erstellen und unseren JavaScript-Code darin schreiben. Erstellen Sie eine <code>index.js</code> Datei im selben Verzeichnis wie Ihre HTML-Datei.</p>\n</li>\n<li>\n<p>Wir beginnen damit, Referenzen zu allen HTML-Features zu erstellen, die wir in diesem Beispiel manipulieren müssen – wir erstellen sie alle als Konstanten, da sich diese Referenzen im Lebenszyklus der App nicht ändern müssen. Fügen Sie die folgenden Zeilen zu Ihrer JavaScript-Datei hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// create needed constants\nconst rememberDiv = document.querySelector(\".remember\");\nconst forgetDiv = document.querySelector(\".forget\");\nconst form = document.querySelector(\"form\");\nconst nameInput = document.querySelector(\"#entername\");\nconst submitBtn = document.querySelector(\"#submitname\");\nconst forgetBtn = document.querySelector(\"#forgetname\");\n\nconst h1 = document.querySelector(\"h1\");\nconst personalGreeting = document.querySelector(\".personal-greeting\");\n</code></pre></div>\n</li>\n<li>\n<p>Als Nächstes müssen wir einen kleinen Ereignis-Listener hinzufügen, um zu verhindern, dass das Formular tatsächlich versendet wird, wenn der Absendebutton gedrückt wird, da dies nicht das Verhalten ist, das wir wünschen. Fügen Sie dieses Snippet unter Ihren vorherigen Code hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Stop the form from submitting when a button is pressed\nform.addEventListener(\"submit\", (e) => e.preventDefault());\n</code></pre></div>\n</li>\n<li>\n<p>Nun müssen wir einen Ereignis-Listener hinzufügen, dessen Handlerfunktion ausgeführt wird, wenn der \"Say hello\"-Button geklickt wird. Die Kommentare erklären detailliert, was jeder Teil macht, aber im Wesentlichen nehmen wir hier den Namen, den der Nutzer in das Text-Eingabefeld eingegeben hat und speichern ihn im Webspeicher mit <code>setItem()</code>, dann führen wir eine Funktion namens <code>nameDisplayCheck()</code> aus, die das tatsächliche Webseiten-Text Update behandelt. Fügen Sie dies unten in Ihren Code ein:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// run function when the 'Say hello' button is clicked\nsubmitBtn.addEventListener(\"click\", () => {\n // store the entered name in web storage\n localStorage.setItem(\"name\", nameInput.value);\n // run nameDisplayCheck() to sort out displaying the personalized greetings and updating the form display\n nameDisplayCheck();\n});\n</code></pre></div>\n</li>\n<li>\n<p>An diesem Punkt benötigen wir auch einen Ereignishandler, der eine Funktion ausführt, wenn der \"Vergessen\"-Button geklickt wird – dieser wird nur angezeigt, nachdem der \"Say hello\"-Button geklickt wurde (die zwei Formularzustände wechseln sich ab). In dieser Funktion entfernen wir das <code>name</code> Item aus dem Webspeicher mit <code>removeItem()</code>, dann führen wir erneut <code>nameDisplayCheck()</code> aus, um die Anzeige zu aktualisieren. Fügen Sie dies am Ende hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// run function when the 'Forget' button is clicked\nforgetBtn.addEventListener(\"click\", () => {\n // Remove the stored name from web storage\n localStorage.removeItem(\"name\");\n // run nameDisplayCheck() to sort out displaying the generic greeting again and updating the form display\n nameDisplayCheck();\n});\n</code></pre></div>\n</li>\n<li>\n<p>Nun ist es an der Zeit die Funktion <code>nameDisplayCheck()</code> selbst zu definieren. Hier prüfen wir, ob das <code>name</code> Item im Webspeicher gespeichert wurde, indem wir <code>localStorage.getItem('name')</code> als Bedingungstest verwenden. Wenn der Name gespeichert wurde, wird dieser Aufruf zu <code>true</code> ausgewertet; wenn nicht, wird der Aufruf zu <code>false</code> ausgewertet. Wenn der Aufruf zu <code>true</code> ausgewertet wird, zeigen wir eine personalisierte Begrüßung an, zeigen den \"vergessen\"-Teil des Formulars an, und verbergen den \"Say hello\"-Teil des Formulars. Wird der Aufruf zu <code>false</code> ausgewertet, wird eine generische Begrüßung angezeigt und das Gegenteil gemacht. Setzen Sie den folgenden Code erneut unten ein:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// define the nameDisplayCheck() function\nfunction nameDisplayCheck() {\n // check whether the 'name' data item is stored in web Storage\n if (localStorage.getItem(\"name\")) {\n // If it is, display personalized greeting\n const name = localStorage.getItem(\"name\");\n h1.textContent = `Welcome, ${name}`;\n personalGreeting.textContent = `Welcome to our website, ${name}! We hope you have fun while you are here.`;\n // hide the 'remember' part of the form and show the 'forget' part\n forgetDiv.style.display = \"block\";\n rememberDiv.style.display = \"none\";\n } else {\n // if not, display generic greeting\n h1.textContent = \"Welcome to our website \";\n personalGreeting.textContent =\n \"Welcome to our website. We hope you have fun while you are here.\";\n // hide the 'forget' part of the form and show the 'remember' part\n forgetDiv.style.display = \"none\";\n rememberDiv.style.display = \"block\";\n }\n}\n</code></pre></div>\n</li>\n<li>\n<p>Zu guter Letzt müssen wir die Funktion <code>nameDisplayCheck()</code> ausführen, wenn die Seite geladen wird. Wenn wir dies nicht tun, wird die personalisierte Begrüßung nicht über Seitenladevorgänge hinweg bestehen bleiben. Fügen Sie das Folgende am Ende Ihres Codes hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>nameDisplayCheck();\n</code></pre></div>\n</li>\n</ol>\n<p>Ihr Beispiel ist fertig – gut gemacht! Alles, was noch fehlt, ist, Ihren Code zu speichern und Ihre HTML-Seite in einem Browser zu testen. Sie können unsere <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/personal-greeting.html\" class=\"external\" target=\"_blank\">fertige Version hier live in Aktion sehen</a>.</p>\n<div class=\"notecard note\">\n<p><strong>Hinweis:</strong>\nEs gibt ein weiteres, etwas komplexeres Beispiel, das Sie unter <a href=\"/de/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API\">Verwendung der Web Storage API</a> erkunden können.</p>\n</div>\n<div class=\"notecard note\">\n<p><strong>Hinweis:</strong>\nIn der Zeile <code><script src=\"index.js\" defer></script></code> des Quellcodes unserer fertigen Version gibt das <code>defer</code> Attribut an, dass der Inhalt des <a href=\"/de/docs/Web/HTML/Element/script\"><code><script></code></a> Elements nicht ausgeführt wird, bis die Seite fertig geladen ist.</p>\n</div>"}},{"type":"prose","value":{"id":"speichern_komplexer_daten_–_indexeddb","title":"Speichern komplexer Daten – IndexedDB","isH3":false,"content":"<p>Die <a href=\"/de/docs/Web/API/IndexedDB_API\">IndexedDB API</a> (manchmal abgekürzt als IDB) ist ein vollständiges Datenbanksystem, das im Browser verfügbar ist, in dem Sie komplexe, verwandte Daten speichern können, deren Typen nicht auf einfache Werte wie Strings oder Zahlen beschränkt sind. Sie können Videos, Bilder und so ziemlich alles andere in einer IndexedDB-Instanz speichern.</p>\n<p>Die IndexedDB API ermöglicht es Ihnen, eine Datenbank zu erstellen und dann Objekt-Speicher innerhalb dieser Datenbank zu erstellen. Objekt-Speicher sind wie Tabellen in einer relationalen Datenbank, und jeder Objekt-Speicher kann eine Anzahl von Objekten enthalten. Um mehr über die IndexedDB API zu erfahren, siehe <a href=\"/de/docs/Web/API/IndexedDB_API/Using_IndexedDB\">Verwendung von IndexedDB</a>.</p>\n<p>Allerdings hat dies seinen Preis: IndexedDB ist viel komplexer zu verwenden als die Web Storage API. In diesem Abschnitt werden wir wirklich nur an der Oberfläche dessen kratzen, wozu sie fähig ist, aber wir geben Ihnen genug, um anzufangen.</p>"}},{"type":"prose","value":{"id":"ein_beispiel_zur_notizspeicherung","title":"Ein Beispiel zur Notizspeicherung","isH3":true,"content":"<p>Hier führen wir Sie durch ein Beispiel, das Ihnen ermöglicht, Notizen in Ihrem Browser zu speichern und sie wann immer Sie möchten anzusehen und zu löschen, indem Sie es für sich selbst aufbauen und die grundlegendsten Teile von IDB erklären, während wir fortfahren.</p>\n<p>Die App sieht ungefähr so aus:</p>\n<p><img src=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage/idb-demo.png\" alt=\"IndexDB Notizen-Demo-Screenshot mit 4 Abschnitten. Der erste Abschnitt ist der Header. Der zweite Abschnitt listet alle Notizen auf, die erstellt wurden. Es gibt zwei Notizen, jede mit einem Löschen-Button. Ein dritter Abschnitt ist ein Formular mit 2 Eingabefeldern für 'Titel der Notiz' und 'Text der Notiz' und einem Button mit der Bezeichnung 'Neue Notiz erstellen'. Der untere Abschnitt Fußzeile liest 'Copyright nobody. Use the code as you like'.\" width=\"803\" height=\"736\" loading=\"lazy\"></p>\n<p>Jede Notiz hat einen Titel und einen Textkörper, beide individuell bearbeitbar. Der JavaScript-Code, den wir im Folgenden durchgehen, enthält detaillierte Kommentare, die Ihnen helfen, zu verstehen, was vor sich geht.</p>"}},{"type":"prose","value":{"id":"grundlagen_starten","title":"Grundlagen starten","isH3":true,"content":"<ol>\n<li>Erstellen Sie zunächst lokale Kopien unserer <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/index.html\" class=\"external\" target=\"_blank\"><code>index.html</code></a>, <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/style.css\" class=\"external\" target=\"_blank\"><code>style.css</code></a> und <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/index-start.js\" class=\"external\" target=\"_blank\"><code>index-start.js</code></a> Dateien in einem neuen Verzeichnis auf Ihrer lokalen Maschine.</li>\n<li>Sehen Sie sich die Dateien an. Sie werden sehen, dass das HTML eine Website mit einer Kopfzeile und einer Fußzeile sowie einen Hauptinhaltbereich definiert, der einen Platz zum Anzeigen von Notizen und ein Formular zum Eingeben neuer Notizen in die Datenbank enthält. Das CSS sorgt für etwas Styling, um klarer zu machen, was vor sich geht. Die JavaScript-Datei enthält fünf deklarierte Konstanten, die Verweise auf das <a href=\"/de/docs/Web/HTML/Element/ul\"><code><ul></code></a>-Element enthalten, in dem die Notizen angezeigt werden; die <a href=\"/de/docs/Web/HTML/Element/input\"><code><input></code></a>-Elemente für Titel und Text, das <a href=\"/de/docs/Web/HTML/Element/form\"><code><form></code></a> selbst und der <a href=\"/de/docs/Web/HTML/Element/button\"><code><button></code></a>.</li>\n<li>Benennen Sie Ihre JavaScript-Datei in <code>index.js</code> um. Sie sind jetzt bereit, Code hinzuzufügen.</li>\n</ol>"}},{"type":"prose","value":{"id":"datenbank-grundeinrichtung","title":"Datenbank-Grundeinrichtung","isH3":true,"content":"<p>Schauen wir uns nun an, was wir eigentlich tun müssen, um eine Datenbank einzurichten.</p>\n<ol>\n<li>\n<p>Fügen Sie unter den Konstantendeklarationen die folgenden Zeilen hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Create an instance of a db object for us to store the open database in\nlet db;\n</code></pre></div>\n<p>Hier erklären wir eine Variable namens <code>db</code> – diese wird später verwendet, um ein Objekt zu speichern, das unsere Datenbank repräsentiert. Wir werden dies an einigen Stellen verwenden, also haben wir es hier global deklariert, um die Dinge zu erleichtern.</p>\n</li>\n<li>\n<p>Fügen Sie als Nächstes die folgenden Zeilen hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Open our database; it is created if it doesn't already exist\n// (see the upgradeneeded handler below)\nconst openRequest = window.indexedDB.open(\"notes_db\", 1);\n</code></pre></div>\n<p>Diese Zeile erstellt eine Anfrage zum Öffnen von Version <code>1</code> einer Datenbank namens <code>notes_db</code>. Wenn diese nicht bereits existiert, wird sie durch nachfolgenden Code für Sie erstellt. Sie werden dieses Anfrage-Muster sehr häufig in IndexedDB sehen. Datenbankoperationen benötigen Zeit. Sie möchten nicht, dass der Browser hängt, während Sie auf die Ergebnisse warten, also sind Datenbankoperationen <a href=\"/de/docs/Glossary/Asynchronous\">asynchron</a>, was bedeutet, dass sie nicht sofort geschehen, sondern irgendwann in der Zukunft, und Sie werden benachrichtigt, wenn sie abgeschlossen sind.</p>\n<p>Um dies in IndexedDB zu handhaben, erstellen Sie ein Anforderungsobjekt (das wie Sie möchten genannt werden kann – wir haben es hier <code>openRequest</code> genannt, damit klar ist, wofür es ist). Sie verwenden dann Ereignis-Handler, um Code auszuführen, wenn die Anfrage abgeschlossen, fehlgeschlagen usw. ist. Dies werden Sie unten in Anwendung sehen.</p>\n<div class=\"notecard note\">\n<p><strong>Hinweis:</strong>\nDie Versionsnummer ist wichtig. Wenn Sie Ihre Datenbank aktualisieren möchten (z. B. durch Ändern der Tabellenstruktur), müssen Sie Ihren Code erneut mit einer erhöhten Versionsnummer ausführen, einem anderen im <code>upgradeneeded</code> Handler spezifizierten Schema (siehe unten) usw. Wir werden die Aktualisierung von Datenbanken in diesem Tutorial nicht behandeln.</p>\n</div>\n</li>\n<li>\n<p>Fügen Sie nun die folgenden Ereignis-Handler direkt unter Ihrer vorherigen Ergänzung hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// error handler signifies that the database didn't open successfully\nopenRequest.addEventListener(\"error\", () =>\n console.error(\"Database failed to open\"),\n);\n\n// success handler signifies that the database opened successfully\nopenRequest.addEventListener(\"success\", () => {\n console.log(\"Database opened successfully\");\n\n // Store the opened database object in the db variable. This is used a lot below\n db = openRequest.result;\n\n // Run the displayData() function to display the notes already in the IDB\n displayData();\n});\n</code></pre></div>\n<p>Der <a href=\"/de/docs/Web/API/IDBRequest/error_event\"><code>error</code></a> Ereignis-Handler wird ausgeführt, wenn das System zurückkommt und sagt, dass die Anfrage fehlgeschlagen ist. Dadurch können Sie auf dieses Problem reagieren. In unserem Beispiel drucken wir einfach eine Nachricht in die JavaScript-Konsole.</p>\n<p>Der <a href=\"/de/docs/Web/API/IDBRequest/success_event\"><code>success</code></a> Ereignis-Handler wird ausgeführt, wenn die Anforderung erfolgreich abgeschlossen wurde, was bedeutet, dass die Datenbank erfolgreich geöffnet wurde. Wenn dies der Fall ist, wird ein Objekt, das die geöffnete Datenbank darstellt, in der <a href=\"/de/docs/Web/API/IDBRequest/result\"><code>openRequest.result</code></a> Eigenschaft verfügbar, wodurch wir die Datenbank manipulieren können. Wir speichern dies in der <code>db</code> Variablen, die wir zuvor für die spätere Verwendung erstellt haben. Wir führen auch eine Funktion namens <code>displayData()</code> aus, die die Daten in der Datenbank innerhalb des <a href=\"/de/docs/Web/HTML/Element/ul\"><code><ul></code></a> anzeigt. Wir führen sie jetzt aus, damit die in der Datenbank bereits vorhandenen Notizen sofort angezeigt werden, wenn die Seite geladen wird. Sie sehen <code>displayData()</code> später definiert.</p>\n</li>\n<li>\n<p>Schließlich für diesen Abschnitt fügen wir wahrscheinlich den wichtigsten Ereignis-Handler zur Einrichtung der Datenbank hinzu: <a href=\"/de/docs/Web/API/IDBOpenDBRequest/upgradeneeded_event\"><code>upgradeneeded</code></a>. Dieser Handler wird ausgeführt, wenn die Datenbank noch nicht eingerichtet wurde oder wenn die Datenbank mit einer höheren Versionsnummer als der in der vorhandenen gespeicherten Datenbank geöffnet wird (bei einem Upgrade). Fügen Sie den folgenden Code unter Ihrem vorherigen Handler hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Set up the database tables if this has not already been done\nopenRequest.addEventListener(\"upgradeneeded\", (e) => {\n // Grab a reference to the opened database\n db = e.target.result;\n\n // Create an objectStore in our database to store notes and an auto-incrementing key\n // An objectStore is similar to a 'table' in a relational database\n const objectStore = db.createObjectStore(\"notes_os\", {\n keyPath: \"id\",\n autoIncrement: true,\n });\n\n // Define what data items the objectStore will contain\n objectStore.createIndex(\"title\", \"title\", { unique: false });\n objectStore.createIndex(\"body\", \"body\", { unique: false });\n\n console.log(\"Database setup complete\");\n});\n</code></pre></div>\n<p>Hier definieren wir das Schema (die Struktur) unserer Datenbank; das heißt, die Reihe von Spalten (oder Feldern), die sie enthält. Hier holen wir zuerst eine Referenz zur vorhandenen Datenbank aus der <code>result</code> Eigenschaft des Zielobjekts des Ereignisses (<code>e.target.result</code>), das das <code>request</code>-Objekt ist. Dies entspricht der Zeile <code>db = openRequest.result;</code> im <code>success</code>-Ereignis-Handler, aber wir müssen dies hier separat tun, weil der <code>upgradeneeded</code> Ereignis-Handler (falls erforderlich) vor dem <code>success</code> Ereignis-Handler ausgeführt wird, was bedeutet, dass der <code>db</code> Wert nicht verfügbar wäre, wenn wir dies nicht tun würden.</p>\n<p>Wir verwenden dann <a href=\"/de/docs/Web/API/IDBDatabase/createObjectStore\"><code>IDBDatabase.createObjectStore()</code></a> zum Erstellen eines neuen Objekt-Speichers in unserer geöffneten Datenbank namens <code>notes_os</code>. Dies entspricht einer einzelnen Tabelle in einem konventionellen Datenbanksystem. Wir haben es den Namen Notizen gegeben und ein <code>autoIncrement</code> Schlüssel-Feld genannt <code>id</code> spezifiziert – in jedem neuen Datensatz wird dies automatisch mit einem inkrementierten Wert vergeben – der Entwickler muss dies nicht explizit festlegen. Als Schlüssel wird das Feld <code>id</code> verwendet, um Datensätze eindeutig zu identifizieren, wie z. B. beim Löschen oder Anzeigen eines Datensatzes.</p>\n<p>Wir erstellen auch zwei weitere Indizes (Felder) mit der Methode <a href=\"/de/docs/Web/API/IDBObjectStore/createIndex\"><code>IDBObjectStore.createIndex()</code></a>: <code>title</code> (das einen Titel für jede Notiz enthalten wird) und <code>body</code> (das den Textkörper der Notiz enthalten wird).</p>\n</li>\n</ol>\n<p>Mit diesem Datenbankschema eingerichtet, wird jeder Datensatz, den wir der Datenbank hinzufügen, als ein Objekt entlang dieser Linien dargestellt:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">json</span></div><pre class=\"brush: json notranslate\"><code>{\n \"title\": \"Buy milk\",\n \"body\": \"Need both cows milk and soy.\",\n \"id\": 8\n}\n</code></pre></div>"}},{"type":"prose","value":{"id":"hinzufügen_von_daten_zur_datenbank","title":"Hinzufügen von Daten zur Datenbank","isH3":true,"content":"<p>Schauen wir uns nun an, wie wir Datensätze zur Datenbank hinzufügen können. Dies wird über das Formular auf unserer Seite geschehen.</p>\n<p>Fügen Sie unter Ihrem vorherigen Ereignis-Handler die folgende Zeile hinzu, die einen <code>submit</code>-Ereignis-Handler festlegt, der eine Funktion namens <code>addData()</code> ausführt, wenn das Formular abgesendet wird (wenn der Absende-<a href=\"/de/docs/Web/HTML/Element/button\"><code><button></code></a> gedrückt wird, was zu einer erfolgreichen Formularübermittlung führt):</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 submit event handler so that when the form is submitted the addData() function is run\nform.addEventListener(\"submit\", addData);\n</code></pre></div>\n<p>Nun definieren wir die Funktion <code>addData()</code>. Fügen Sie diese unter Ihrer vorherigen Zeile hinzu:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Define the addData() function\nfunction addData(e) {\n // prevent default - we don't want the form to submit in the conventional way\n e.preventDefault();\n\n // grab the values entered into the form fields and store them in an object ready for being inserted into the DB\n const newItem = { title: titleInput.value, body: bodyInput.value };\n\n // open a read/write db transaction, ready for adding the data\n const transaction = db.transaction([\"notes_os\"], \"readwrite\");\n\n // call an object store that's already been added to the database\n const objectStore = transaction.objectStore(\"notes_os\");\n\n // Make a request to add our newItem object to the object store\n const addRequest = objectStore.add(newItem);\n\n addRequest.addEventListener(\"success\", () => {\n // Clear the form, ready for adding the next entry\n titleInput.value = \"\";\n bodyInput.value = \"\";\n });\n\n // Report on the success of the transaction completing, when everything is done\n transaction.addEventListener(\"complete\", () => {\n console.log(\"Transaction completed: database modification finished.\");\n\n // update the display of data to show the newly added item, by running displayData() again.\n displayData();\n });\n\n transaction.addEventListener(\"error\", () =>\n console.log(\"Transaction not opened due to error\"),\n );\n}\n</code></pre></div>\n<p>Dies ist ziemlich komplex; nutzen wir dies, um es herunterzubrechen:</p>\n<ul>\n<li>Wir führen <a href=\"/de/docs/Web/API/Event/preventDefault\"><code>Event.preventDefault()</code></a> für das Ereignis-Objekt aus, um zu verhindern, dass das Formular tatsächlich auf herkömmliche Weise abgesendet wird (dies würde ein Seiten-Neuladen verursachen und die Erfahrung verderben).</li>\n<li>Wir erstellen ein Objekt, das einen Datensatz repräsentiert, der in die Datenbank eingefügt werden soll und mit Werten aus den Formulareingaben gefüllt wird. Beachten Sie, dass wir nicht explizit einen <code>id</code> Wert einbeziehen müssen – wie bereits erwähnt, wird dies automatisch gefüllt.</li>\n<li>Wir öffnen eine <code>readwrite</code> Transaktion gegen den <code>notes_os</code> Objektspeicher mit der Methode <a href=\"/de/docs/Web/API/IDBDatabase/transaction\"><code>IDBDatabase.transaction()</code></a>. Dieses Transaktionsobjekt ermöglicht es uns, auf den Objektspeicher zuzugreifen, damit wir etwas damit tun können, z.B. einen neuen Datensatz hinzufügen.</li>\n<li>Wir greifen mit der Methode <a href=\"/de/docs/Web/API/IDBTransaction/objectStore\"><code>IDBTransaction.objectStore()</code></a> auf den Objektspeicher zu und speichern das Ergebnis in der Variablen <code>objectStore</code>.</li>\n<li>Wir fügen den neuen Datensatz mit <a href=\"/de/docs/Web/API/IDBObjectStore/add\"><code>IDBObjectStore.add()</code></a> zur Datenbank hinzu. Dies erstellt ein Anforderungsobjekt, so wie wir es zuvor gesehen haben.</li>\n<li>Wir fügen eine Reihe von Ereignis-Handlern zu den Objekten <code>request</code> und <code>transaction</code> hinzu, um Code an kritischen Punkten im Lebenszyklus auszuführen. Sobald die Anforderung erfolgreich war, löschen wir die Formulareingaben, um die nächste Notiz einzugeben. Sobald die Transaktion abgeschlossen ist, führen wir die <code>displayData()</code> Funktion erneut aus, um die Anzeige der Notizen auf der Seite zu aktualisieren.</li>\n</ul>"}},{"type":"prose","value":{"id":"anzeigen_der_daten","title":"Anzeigen der Daten","isH3":true,"content":"<p>Wir haben <code>displayData()</code> bereits zweimal in unserem Code referenziert, also sollten wir es wahrscheinlich definieren. Fügen Sie dies zu Ihrem Code hinzu, unter der vorherigen Funktionsdefinition:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Define the displayData() function\nfunction displayData() {\n // Here we empty the contents of the list element each time the display is updated\n // If you didn't do this, you'd get duplicates listed each time a new note is added\n while (list.firstChild) {\n list.removeChild(list.firstChild);\n }\n\n // Open our object store and then get a cursor - which iterates through all the\n // different data items in the store\n const objectStore = db.transaction(\"notes_os\").objectStore(\"notes_os\");\n objectStore.openCursor().addEventListener(\"success\", (e) => {\n // Get a reference to the cursor\n const cursor = e.target.result;\n\n // If there is still another data item to iterate through, keep running this code\n if (cursor) {\n // Create a list item, h3, and p to put each data item inside when displaying it\n // structure the HTML fragment, and append it inside the list\n const listItem = document.createElement(\"li\");\n const h3 = document.createElement(\"h3\");\n const para = document.createElement(\"p\");\n\n listItem.appendChild(h3);\n listItem.appendChild(para);\n list.appendChild(listItem);\n\n // Put the data from the cursor inside the h3 and para\n h3.textContent = cursor.value.title;\n para.textContent = cursor.value.body;\n\n // Store the ID of the data item inside an attribute on the listItem, so we know\n // which item it corresponds to. This will be useful later when we want to delete items\n listItem.setAttribute(\"data-note-id\", cursor.value.id);\n\n // Create a button and place it inside each listItem\n const deleteBtn = document.createElement(\"button\");\n listItem.appendChild(deleteBtn);\n deleteBtn.textContent = \"Delete\";\n\n // Set an event handler so that when the button is clicked, the deleteItem()\n // function is run\n deleteBtn.addEventListener(\"click\", deleteItem);\n\n // Iterate to the next item in the cursor\n cursor.continue();\n } else {\n // Again, if list item is empty, display a 'No notes stored' message\n if (!list.firstChild) {\n const listItem = document.createElement(\"li\");\n listItem.textContent = \"No notes stored.\";\n list.appendChild(listItem);\n }\n // if there are no more cursor items to iterate through, say so\n console.log(\"Notes all displayed\");\n }\n });\n}\n</code></pre></div>\n<p>Brechen wir dies erneut auseinander:</p>\n<ul>\n<li>Zuerst leeren wir den Inhalt des <a href=\"/de/docs/Web/HTML/Element/ul\"><code><ul></code></a> Elements, bevor wir es dann mit dem aktualisierten Inhalt füllen. Wenn Sie dies nicht tun würden, würden Sie eine riesige Liste duplizierter Inhalte haben, die bei jedem Update hinzugefügt wird.</li>\n<li>Als Nächstes erhalten wir eine Referenz zum <code>notes_os</code> Objektspeicher mit <a href=\"/de/docs/Web/API/IDBDatabase/transaction\"><code>IDBDatabase.transaction()</code></a> und <a href=\"/de/docs/Web/API/IDBTransaction/objectStore\"><code>IDBTransaction.objectStore()</code></a> genauso, wie wir es in <code>addData()</code> getan haben, außer dass wir sie hier in einer Zeile verketten.</li>\n<li>Der nächste Schritt ist die Verwendung der Methode <a href=\"/de/docs/Web/API/IDBObjectStore/openCursor\"><code>IDBObjectStore.openCursor()</code></a>, um eine Anfrage für einen Cursor zu öffnen – dies ist ein Konstrukt, das zum Durchlaufen der Datensätze in einem Objektspeicher verwendet werden kann. Wir verketten einen <code>success</code> Ereignis-Handler an das Ende dieser Zeile, um den Code prägnanter zu gestalten – wenn der Cursor erfolgreich zurückgegeben wird, wird der Handler ausgeführt.</li>\n<li>Wir erhalten eine Referenz auf den Cursor selbst (ein <a href=\"/de/docs/Web/API/IDBCursor\"><code>IDBCursor</code></a> Objekt) mit <code>const cursor = e.target.result</code>.</li>\n<li>Als Nächstes prüfen wir, ob der Cursor einen Datensatz aus dem Datenspeicher enthält (<code>if (cursor){ }</code>) – wenn ja, erstellen wir einen DOM-Fragment, füllen es mit den Daten des Datensatzes und fügen es in die Seite ein (innerhalb des <code><ul></code> Elements). Wir fügen auch einen Löschen-Button hinzu, der, wenn er geklickt wird, diese Notiz durch Ausführen der Funktion <code>deleteItem()</code> löschen wird, die wir im nächsten Abschnitt betrachten werden.</li>\n<li>Am Ende des <code>if</code> Blocks verwenden wir die Methode <a href=\"/de/docs/Web/API/IDBCursor/continue\"><code>IDBCursor.continue()</code></a>, um den Cursor zum nächsten Datensatz im Datenspeicher zu verschieben und den Inhalt des <code>if</code> Blocks erneut auszuführen. Wenn es einen weiteren Datensatz zu durchlaufen gibt, führt dies dazu, dass er in die Seite eingefügt wird, und dann wird <code>continue()</code> erneut ausgeführt und so weiter.</li>\n<li>Wenn keine weiteren Datensätze zur Iteration vorhanden sind, wird <code>cursor</code> <code>undefined</code> zurückgeben, und deshalb wird der <code>else</code> Block anstelle des <code>if</code> Blocks ausgeführt. Dieser Block prüft, ob Notizen in das <code><ul></code> eingefügt wurden – falls nicht, fügt er eine Nachricht ein, dass keine Notiz gespeichert wurde.</li>\n</ul>"}},{"type":"prose","value":{"id":"eine_notiz_löschen","title":"Eine Notiz löschen","isH3":true,"content":"<p>Wie oben erwähnt, wenn der Lösch-Button einer Notiz gedrückt wird, wird die Notiz gelöscht. Dies geschieht durch die Funktion <code>deleteItem()</code>:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Define the deleteItem() function\nfunction deleteItem(e) {\n // retrieve the name of the task we want to delete. We need\n // to convert it to a number before trying to use it with IDB; IDB key\n // values are type-sensitive.\n const noteId = Number(e.target.parentNode.getAttribute(\"data-note-id\"));\n\n // open a database transaction and delete the task, finding it using the id we retrieved above\n const transaction = db.transaction([\"notes_os\"], \"readwrite\");\n const objectStore = transaction.objectStore(\"notes_os\");\n const deleteRequest = objectStore.delete(noteId);\n\n // report that the data item has been deleted\n transaction.addEventListener(\"complete\", () => {\n // delete the parent of the button\n // which is the list item, so it is no longer displayed\n e.target.parentNode.parentNode.removeChild(e.target.parentNode);\n console.log(`Note ${noteId} deleted.`);\n\n // Again, if list item is empty, display a 'No notes stored' message\n if (!list.firstChild) {\n const listItem = document.createElement(\"li\");\n listItem.textContent = \"No notes stored.\";\n list.appendChild(listItem);\n }\n });\n}\n</code></pre></div>\n<ul>\n<li>Der erste Teil davon könnte etwas Erklärung benötigen – wir rufen die ID des zu löschenden Datensatzes mit <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> ab – erinnern Sie sich, dass die ID des Datensatzes in einem <code>data-note-id</code> Attribut auf dem <code><li></code> gespeichert wurde, als es zuerst angezeigt wurde. Wir müssen das Attribut jedoch durch das globale eingebaute Objekt <a href=\"/de/docs/Web/JavaScript/Reference/Global_Objects/Number\"><code>Number()</code></a> laufen lassen, da es vom Datentyp String ist und daher nicht von der Datenbank erkannt würde, die eine Zahl erwartet.</li>\n<li>Dann erhalten wir eine Referenz auf den Objektspeicher, indem wir das gleiche Muster verwenden, das wir zuvor gesehen haben, und verwenden die Methode <a href=\"/de/docs/Web/API/IDBObjectStore/delete\"><code>IDBObjectStore.delete()</code></a>, um den Datensatz aus der Datenbank zu löschen, und übergeben ihm die ID.</li>\n<li>Wenn die Datenbanktransaktion abgeschlossen ist, löschen wir das <code><li></code> der Notiz aus dem DOM und führen erneut den Check durch, ob das <code><ul></code> nun leer ist und fügen eine entsprechende Notiz ein.</li>\n</ul>\n<p>Das war's! Ihr Beispiel sollte nun funktionieren.</p>\n<p>Wenn Sie damit Schwierigkeiten haben, zögern Sie nicht, <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/\" class=\"external\" target=\"_blank\">es mit unserem Live-Beispiel zu vergleichen</a> (siehe auch den <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/indexeddb/notes/index.js\" class=\"external\" target=\"_blank\">Quellcode</a>).</p>"}},{"type":"prose","value":{"id":"speichern_komplexer_daten_über_indexeddb","title":"Speichern komplexer Daten über IndexedDB","isH3":true,"content":"<p>Wie oben erwähnt, kann IndexedDB verwendet werden, um mehr als nur Textstrings zu speichern. Sie können so ziemlich alles speichern, was Sie möchten, einschließlich komplexer Objekte wie Video- oder Bildblobs. Und es ist nicht viel schwieriger zu erreichen als jede andere Art von Daten.</p>\n<p>Um zu demonstrieren, wie das geht, haben wir ein weiteres Beispiel namens <a href=\"https://github.com/mdn/learning-area/tree/main/javascript/apis/client-side-storage/indexeddb/video-store\" class=\"external\" target=\"_blank\">IndexedDB-Video-Store</a> geschrieben (sehen Sie es <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/\" class=\"external\" target=\"_blank\">auch live hier laufen</a>). Wenn Sie das Beispiel zum ersten Mal ausführen, werden alle Videos aus dem Netzwerk heruntergeladen, in einer IndexedDB-Datenbank gespeichert und dann die Videos innerhalb von <a href=\"/de/docs/Web/HTML/Element/video\"><code><video></code></a>-Elementen in der Benutzeroberfläche angezeigt. Beim zweiten Mal wird geprüft, ob die Videos in der Datenbank vorhanden sind, und sie werden von dort geholt, bevor sie angezeigt werden – dies macht spätere Ladezeiten viel schneller und weniger bandbreitenhungrig.</p>\n<p>Lassen Sie uns die interessantesten Teile des Beispiels durchgehen. Wir werden nicht alles behandeln – Vieles davon ist ähnlich wie das vorherige Beispiel, und der Code ist gut kommentiert.</p>\n<ol>\n<li>\n<p>Für dieses Beispiel haben wir die Namen der abzurufenden Videos in einem Array von Objekten gespeichert:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const videos = [\n { name: \"crystal\" },\n { name: \"elf\" },\n { name: \"frog\" },\n { name: \"monster\" },\n { name: \"pig\" },\n { name: \"rabbit\" },\n];\n</code></pre></div>\n</li>\n<li>\n<p>Zuerst, sobald die Datenbank erfolgreich geöffnet wurde, führen wir eine <code>init()</code> Funktion aus. Diese durchläuft die verschiedenen Videonamen und versucht, einen durch jeden Namen identifizierten Datensatz aus der <code>videos</code> Datenbank zu laden.</p>\n<p>Wenn jedes Video in der Datenbank gefunden wird (überprüft durch das Sehen, ob <code>request.result</code> zu <code>true</code> ausgewertet wird – wenn der Datensatz nicht vorhanden ist, wird er <code>undefined</code> sein), werden seine Videodateien (gespeichert als Blobs) und der Name des Videos direkt an die Funktion <code>displayVideo()</code> übergeben, um sie in der Benutzeroberfläche zu platzieren. Falls nicht, wird der Videoname an die Funktion <code>fetchVideoFromNetwork()</code> übergeben, um das Video aus dem Netzwerk zu holen.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>function init() {\n // Loop through the video names one by one\n for (const video of videos) {\n // Open transaction, get object store, and get() each video by name\n const objectStore = db.transaction(\"videos_os\").objectStore(\"videos_os\");\n const request = objectStore.get(video.name);\n request.addEventListener(\"success\", () => {\n // If the result exists in the database (is not undefined)\n if (request.result) {\n // Grab the videos from IDB and display them using displayVideo()\n console.log(\"taking videos from IDB\");\n displayVideo(\n request.result.mp4,\n request.result.webm,\n request.result.name,\n );\n } else {\n // Fetch the videos from the network\n fetchVideoFromNetwork(video);\n }\n });\n }\n}\n</code></pre></div>\n</li>\n<li>\n<p>Das folgende Snippet stammt aus dem Inneren von <code>fetchVideoFromNetwork()</code> – hier holen wir MP4- und WebM-Versionen des Videos mit zwei separaten <a href=\"/de/docs/Web/API/Window/fetch\"><code>fetch()</code></a> Anfragen. Wir verwenden dann die Methode <a href=\"/de/docs/Web/API/Response/blob\"><code>Response.blob()</code></a>, um den Körper jeder Antwort als Blob zu extrahieren, was uns eine Objektrepräsentation der Videos gibt, die später gespeichert und angezeigt werden kann.</p>\n<p>Wir haben hier jedoch ein Problem – diese beiden Anfragen sind asynchron, aber wir möchten versuchen, das Video nur dann anzuzeigen oder zu speichern, wenn beide Versprechen erfüllt sind. Glücklicherweise gibt es eine eingebaute Methode, die ein solches Problem handhabt – <a href=\"/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/all\"><code>Promise.all()</code></a>. Diese nimmt ein Argument – Verweise auf alle einzelnen Versprechen, die Sie auf Erfüllung prüfen möchten, platziert in einem Array – und gibt ein Versprechen zurück, das erfüllt ist, wenn alle einzelnen Versprechen erfüllt sind.</p>\n<p>Im <code>then()</code> Handler für dieses Versprechen rufen wir die Funktion <code>displayVideo()</code> auf, genau wie zuvor, um die Videos in der Benutzeroberfläche anzuzeigen, dann rufen wir auch die Funktion <code>storeVideo()</code> auf, um diese Videos in der Datenbank zu speichern.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Fetch the MP4 and WebM versions of the video using the fetch() function,\n// then expose their response bodies as blobs\nconst mp4Blob = fetch(`videos/${video.name}.mp4`).then((response) =>\n response.blob(),\n);\nconst webmBlob = fetch(`videos/${video.name}.webm`).then((response) =>\n response.blob(),\n);\n\n// Only run the next code when both promises have fulfilled\nPromise.all([mp4Blob, webmBlob]).then((values) => {\n // display the video fetched from the network with displayVideo()\n displayVideo(values[0], values[1], video.name);\n // store it in the IDB using storeVideo()\n storeVideo(values[0], values[1], video.name);\n});\n</code></pre></div>\n</li>\n<li>\n<p>Schauen wir uns zuerst <code>storeVideo()</code> an. Dies ist dem Muster, das Sie im vorherigen Beispiel für das Hinzufügen von Daten zur Datenbank gesehen haben, sehr ähnlich – wir öffnen eine <code>readwrite</code> Transaktion und erhalten eine Referenz auf unseren <code>videos_os</code> Objektspeicher, erstellen ein Objekt, das den zur Datenbank hinzuzufügenden Datensatz repräsentiert, und fügen es dann mit <a href=\"/de/docs/Web/API/IDBObjectStore/add\"><code>IDBObjectStore.add()</code></a> hinzu.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Define the storeVideo() function\nfunction storeVideo(mp4, webm, name) {\n // Open transaction, get object store; make it a readwrite so we can write to the IDB\n const objectStore = db\n .transaction([\"videos_os\"], \"readwrite\")\n .objectStore(\"videos_os\");\n\n // Add the record to the IDB using add()\n const request = objectStore.add({ mp4, webm, name });\n\n request.addEventListener(\"success\", () =>\n console.log(\"Record addition attempt finished\"),\n );\n request.addEventListener(\"error\", () => console.error(request.error));\n}\n</code></pre></div>\n</li>\n<li>\n<p>Schließlich haben wir <code>displayVideo()</code>, das die benötigten DOM-Elemente erstellt, um das Video in der Benutzeroberfläche einzufügen, und sie dann der Seite hinzufügt. Die interessantesten Teile davon sind die unten gezeigten – um tatsächlich unsere Videoblobs in einem <code><video></code>-Element anzuzeigen, müssen wir Objekt-URLs (interne URLs, die auf die in den Speicher geladenen Videoblobs zeigen) mit der Methode <a href=\"/de/docs/Web/API/URL/createObjectURL_static\"><code>URL.createObjectURL()</code></a> erstellen. Sobald das erledigt ist, können wir die Objekt-URLs als Werte der <code>src</code> Attribute unserer <a href=\"/de/docs/Web/HTML/Element/source\"><code><source></code></a> Elemente setzen, und es funktioniert einwandfrei.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Define the displayVideo() function\nfunction displayVideo(mp4Blob, webmBlob, title) {\n // Create object URLs out of the blobs\n const mp4URL = URL.createObjectURL(mp4Blob);\n const webmURL = URL.createObjectURL(webmBlob);\n\n // Create DOM elements to embed video in the page\n const article = document.createElement(\"article\");\n const h2 = document.createElement(\"h2\");\n h2.textContent = title;\n const video = document.createElement(\"video\");\n video.controls = true;\n const source1 = document.createElement(\"source\");\n source1.src = mp4URL;\n source1.type = \"video/mp4\";\n const source2 = document.createElement(\"source\");\n source2.src = webmURL;\n source2.type = \"video/webm\";\n\n // Embed DOM elements into page\n section.appendChild(article);\n article.appendChild(h2);\n article.appendChild(video);\n video.appendChild(source1);\n video.appendChild(source2);\n}\n</code></pre></div>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"offline-asset-speicherung","title":"Offline-Asset-Speicherung","isH3":false,"content":"<p>Das obige Beispiel zeigt bereits, wie man eine App erstellt, die große Assets in einer IndexedDB-Datenbank speichert und das Herunterladen dieser mehr als einmal vermeiden kann. Dies ist bereits eine große Verbesserung der Nutzererfahrung, aber es fehlt noch etwas – die Haupt-HTML-, CSS- und JavaScript-Dateien müssen immer noch jedes Mal heruntergeladen werden, wenn auf die Seite zugegriffen wird, was bedeutet, dass sie bei fehlender Netzwerkverbindung nicht funktionieren würde.</p>\n<p><img src=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage/ff-offline.png\" alt=\"Firefox Offline-Bildschirm mit einer Illustration eines Cartoon-Charakters auf der linken Seite, der einen zwei-Pin-Stecker in seiner rechten Hand und eine zwei-Pin-Buchse in seiner linken Hand hält. Auf der rechten Seite gibt es eine Offline-Modus-Meldung und einen Button mit der Bezeichnung 'Try again'.\" width=\"765\" height=\"307\" loading=\"lazy\"></p>\n<p>An dieser Stelle kommen <a href=\"/de/docs/Web/API/Service_Worker_API\">Service Worker</a> und die eng verwandte <a href=\"/de/docs/Web/API/Cache\">Cache API</a> ins Spiel.</p>\n<p>Ein Service Worker ist eine JavaScript-Datei, die gegen einen bestimmten Ursprung (Website oder Teil einer Website an einer bestimmten Domäne) registriert wird, wenn darauf von einem Browser zugegriffen wird. Wenn sie registriert ist, kann sie die Seiten des Ursprungs steuern, indem sie zwischen einer geladenen Seite und dem Netzwerk sitzt und alle Netzwerk-Anfragen abfängt, die auf diesen Ursprung gerichtet sind.</p>\n<p>Wenn sie eine Anfrage abfängt, kann sie mit der Anfrage alles tun, was Sie möchten (siehe <a href=\"/de/docs/Web/API/Service_Worker_API#other_use_case_ideas\">Use-Case-Ideen</a>), aber das klassische Beispiel ist das Speichern der Netzwerkantworten offline und das Bereitstellen dieser als Antwort auf eine Anfrage statt der Antworten aus dem Netzwerk. Im Effekt ermöglicht es Ihnen, eine Website vollständig offline zu machen.</p>\n<p>Die Cache API ist ein weiteres client-seitiges Speichermechanismus mit einem kleinen Unterschied – es ist dafür ausgelegt, HTTP-Antworten zu speichern und funktioniert daher sehr gut mit Service Workern.</p>"}},{"type":"prose","value":{"id":"ein_service-worker-beispiel","title":"Ein Service-Worker-Beispiel","isH3":true,"content":"<p>Schauen wir uns ein Beispiel an, um Ihnen eine Vorstellung davon zu geben, wie könnte dies aussehen. Wir haben eine andere Version des zuvor in Abschnitt betrachteten Video-Store-Beispiels erstellt – dies funktioniert identisch, außer dass es auch die HTML-, CSS- und JavaScript-Dateien in der Cache API über einen Service Worker speichert, was das Beispiel offline funktionsfähig macht!</p>\n<p>Sehen Sie <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/\" class=\"external\" target=\"_blank\">IndexedDB-Video-Store mit Service Worker live laufen</a>, und sehen Sie auch <a href=\"https://github.com/mdn/learning-area/tree/main/javascript/apis/client-side-storage/cache-sw/video-store-offline\" class=\"external\" target=\"_blank\">den Quellcode</a>.</p>\n<h4 id=\"registrierung_des_service_workers\">Registrierung des Service Workers</h4>\n<p>Das erste, was es zu beachten gibt, ist dass es einen zusätzlichen Codeabschnitt in der Haupt-JavaScript-Datei gibt (siehe <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js\" class=\"external\" target=\"_blank\">index.js</a>). Zuerst machen wir einen Feature-Erkennungstest, um zu sehen, ob das <code>serviceWorker</code> Mitglied im <a href=\"/de/docs/Web/API/Navigator\"><code>Navigator</code></a> Objekt verfügbar ist. Wenn dies <code>true</code> zurückgibt, wissen wir, dass mindestens die Grundlagen der Service Worker unterstützt werden. Hier verwenden wir die Methode <a href=\"/de/docs/Web/API/ServiceWorkerContainer/register\"><code>ServiceWorkerContainer.register()</code></a>, um einen im <code>sw.js</code> Datei enthaltenen Service Worker gegen den Ursprung, an dem er sich befindet, zu registrieren, damit er Seiten im gleichen Verzeichnis wie er oder Unterverzeichnisse steuern kann. Wenn das Versprechen erfüllt ist, wird der Service Worker als registriert angesehen.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>// Register service worker to control making site work offline\nif (\"serviceWorker\" in navigator) {\n navigator.serviceWorker\n .register(\n \"/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js\",\n )\n .then(() => console.log(\"Service Worker Registered\"));\n}\n</code></pre></div>\n<div class=\"notecard note\">\n<p><strong>Hinweis:</strong>\nDer angegebene Pfad zur <code>sw.js</code> Datei ist relativ zum Standort des Ursprungs, nicht die JavaScript-Datei, die den Code enthält. Der Service Worker befindet sich an <code>https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. Der Ursprung ist <code>https://mdn.github.io</code>, und deshalb muss der angegebene Pfad <code>/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code> sein. Wenn Sie dieses Beispiel auf Ihrem eigenen Server hosten möchten, müssten Sie dies entsprechend ändern. Dies ist eher verwirrend, aber es muss aus Sicherheitsgründen so funktionieren.</p>\n</div>\n<h4 id=\"installation_des_service_workers\">Installation des Service Workers</h4>\n<p>Das nächste Mal, wenn auf eine Seite unter der Kontrolle des Service Workers zugegriffen wird (z.B. wenn das Beispiel neu geladen wird), wird der Service Worker gegen diese Seite installiert, was bedeutet, dass er beginnt, sie zu steuern. Wenn dies geschieht, wird ein <code>install</code> Ereignis gegen den Service Worker ausgelöst; Sie können Code innerhalb des Service Worker selbst schreiben, der auf die Installation reagieren wird.</p>\n<p>Schauen wir uns ein Beispiel an, in der <a href=\"https://github.com/mdn/learning-area/blob/main/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js\" class=\"external\" target=\"_blank\">sw.js</a> Datei (dem Service Worker). Sie werden sehen, dass der Installations-Listener gegen <code>self</code> registriert wird. Dieses <code>self</code> Schlüsselwort ist eine Möglichkeit, auf den globalen Bereich des Service Workers von innerhalb der Service-Worker-Datei zu verweisen.</p>\n<p>Innerhalb des <code>install</code> Handlers verwenden wir die Methode <a href=\"/de/docs/Web/API/ExtendableEvent/waitUntil\"><code>ExtendableEvent.waitUntil()</code></a>, die auf dem Ereignis-Objekt verfügbar ist, um anzugeben, dass der Browser die Installation des Service Workers nicht abschließen sollte, bis das Versprechen innerhalb erfolgreich erfüllt wurde.</p>\n<p>Hier sehen wir die Cache API in Aktion. Wir verwenden die Methode <a href=\"/de/docs/Web/API/CacheStorage/open\"><code>CacheStorage.open()</code></a>, um ein neues Cache-Objekt zu öffnen, in dem Antworten gespeichert werden können (ähnlich wie ein IndexedDB-Objektspeicher). Dieses Versprechen erfüllt sich mit einem <a href=\"/de/docs/Web/API/Cache\"><code>Cache</code></a> Objekt, das den <code>video-store</code> Cache repräsentiert. Wir verwenden dann die Methode <a href=\"/de/docs/Web/API/Cache/addAll\"><code>Cache.addAll()</code></a>, um eine Reihe von Assets abzurufen und deren Antworten zum Cache hinzuzufügen.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>self.addEventListener(\"install\", (e) => {\n e.waitUntil(\n caches\n .open(\"video-store\")\n .then((cache) =>\n cache.addAll([\n \"/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/\",\n \"/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html\",\n \"/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js\",\n \"/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css\",\n ]),\n ),\n );\n});\n</code></pre></div>\n<p>Das war's vorerst, Installation fertig.</p>\n<h4 id=\"reagieren_auf_weitere_anfragen\">Reagieren auf weitere Anfragen</h4>\n<p>Mit dem Service Worker registriert und gegen unsere HTML-Seite installiert und den entsprechenden Assets alle zu unserem Cache hinzugefügt, sind wir fast bereit zu gehen. Es gibt nur noch eine Sache zu tun: etwas Code schreiben, um auf weitere Netzwerk-Anfragen zu reagieren.</p>\n<p>Das ist es, was der zweite Code in <code>sw.js</code> tut. Wir fügen einen weiteren Listener zum globalen Bereich des Service Workers hinzu, der die Handler-Funktion ausführt, wenn das <code>fetch</code> Ereignis ausgelöst wird. Dies geschieht, wenn der Browser eine Anfrage für ein Asset in dem Verzeichnis stellt, gegen das der Service Worker registriert ist.</p>\n<p>Innerhalb des Handlers loggen wir zuerst die URL des angeforderten Assets. Dann geben wir eine benutzerdefinierte Antwort auf die Anfrage, mit der Methode <a href=\"/de/docs/Web/API/FetchEvent/respondWith\"><code>FetchEvent.respondWith()</code></a>.</p>\n<p>Innerhalb dieses Blocks überprüfen wir, ob eine passende Anfrage (das heißt, die URL entspricht) in einem Cache gefunden werden kann, indem wir <a href=\"/de/docs/Web/API/CacheStorage/match\"><code>CacheStorage.match()</code></a> verwenden. Dieses Versprechen erfüllt sich mit der passenden Antwort, wenn ein Treffer gefunden wird, oder <code>undefined</code>, wenn nicht.</p>\n<p>Wenn ein Treffer gefunden wird, geben wir ihn als benutzerdefinierte Antwort zurück. Andernfalls rufen wir die Antwort mit einem <a href=\"/de/docs/Web/API/Window/fetch\">fetch()</a> aus dem Netzwerk ab und geben diese stattdessen zurück.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>self.addEventListener(\"fetch\", (e) => {\n console.log(e.request.url);\n e.respondWith(\n caches.match(e.request).then((response) => response || fetch(e.request)),\n );\n});\n</code></pre></div>\n<p>Und das war's für unseren Service Worker. Es gibt noch viel mehr, was Sie mit ihnen tun können – für eine ausführlichere Betrachtung, siehe das <a href=\"https://github.com/mdn/serviceworker-cookbook\" class=\"external\" target=\"_blank\">Service Worker Cookbook</a>. Vielen Dank an Paul Kinlan für seinen Artikel <a href=\"https://developers.google.com/codelabs/pwa-training/pwa03--going-offline#0\" class=\"external\" target=\"_blank\">Adding a Service Worker and Offline into your Web App</a>, der dieses Beispiel inspiriert hat.</p>\n<h4 id=\"testen_des_beispiels_im_offline-modus\">Testen des Beispiels im Offline-Modus</h4>\n<p>Um unser <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/\" class=\"external\" target=\"_blank\">Service Worker Beispiel</a> zu testen, müssen Sie es ein paar Mal laden, um sicherzustellen, dass es installiert ist. Sobald dies geschehen ist, können Sie:</p>\n<ul>\n<li>Versuchen Sie, Ihr Netzwerk auszustecken / Ihre Wi-Fi auszuschalten.</li>\n<li>Wählen Sie <em>Datei > Offline arbeiten</em> wenn Sie Firefox verwenden.</li>\n<li>Gehen Sie zu den Devtools, dann wählen Sie <em>Anwendung > Service Worker</em>, dann markieren Sie das <em>Offline</em> Kontrollkästchen, wenn Sie Chrome verwenden.</li>\n</ul>\n<p>Wenn Sie Ihre Beispielseite erneut laden, sollten Sie sehen, dass sie weiterhin einwandfrei lädt. Alles ist offline gespeichert – die Seite-Assets in einem Cache und die Videos in einer IndexedDB-Datenbank.</p>"}},{"type":"prose","value":{"id":"zusammenfassung","title":"Zusammenfassung","isH3":false,"content":"<p>Das war's für den Moment. Wir hoffen, dass unser Überblick über client-seitige Speichertechnologien für Sie nützlich war.</p>"}},{"type":"prose","value":{"id":"siehe_auch","title":"Siehe auch","isH3":false,"content":"<ul>\n<li><a href=\"/de/docs/Web/API/Web_Storage_API\">Web storage API</a></li>\n<li><a href=\"/de/docs/Web/API/IndexedDB_API\">IndexedDB API</a></li>\n<li><a href=\"/de/docs/Web/HTTP/Cookies\">Cookies</a></li>\n<li><a href=\"/de/docs/Web/API/Service_Worker_API\">Service worker API</a></li>\n</ul>\n<ul class=\"prev-next\"><li><a class=\"button secondary\" href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics\"><span class=\"button-wrap\"> Zurück </span></a></li><li><a class=\"button secondary\" href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs\"><span class=\"button-wrap\"> Übersicht: Client-seitige Web-APIs</span></a></li><li><a class=\"button secondary\" href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs\"><span class=\"button-wrap\"> Weiter </span></a></li></ul>"}}],"isActive":true,"isMarkdown":true,"isTranslated":true,"locale":"de","mdn_url":"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage","modified":"2025-02-17T00:20:27.000Z","native":"Deutsch","noIndexing":false,"other_translations":[{"locale":"en-US","title":"Client-side storage","native":"English (US)"},{"locale":"es","title":"Almacenamiento del lado cliente","native":"Español"},{"locale":"fr","title":"Stockage côté client","native":"Français"},{"locale":"ja","title":"クライアント側ストレージ","native":"日本語"},{"locale":"pt-BR","title":"Client-side storage","native":"Português (do Brasil)"},{"locale":"ru","title":"Client-side storage","native":"Русский"},{"locale":"zh-CN","title":"客户端存储","native":"中文 (简体)"}],"pageTitle":"Client-seitiger Speicher - Lernen Sie Webentwicklung | MDN","parents":[{"uri":"/de/docs/Learn_web_development","title":"Lernen Sie Webentwicklung"},{"uri":"/de/docs/Learn_web_development/Extensions","title":"Erweiterungsmodule"},{"uri":"/de/docs/Learn_web_development/Extensions/Client-side_APIs","title":"Client-seitige Web-APIs"},{"uri":"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage","title":"Client-seitiger Speicher"}],"popularity":null,"short_title":"Client-seitiger Speicher","sidebarHTML":"<ol><li class=\"section\"><a href=\"/de/docs/Learn_web_development/Getting_started\">Einstiegsmodule</a></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Getting_started/Environment_setup\">Umgebung einrichten</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Getting_started/Environment_setup/Installing_software\">Installation grundlegender Software</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web\">Surfen im Web</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Environment_setup/Code_editors\">Code-Editor</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Environment_setup/Dealing_with_files\">Umgang mit Dateien</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Environment_setup/Command_line\">Leitfaden für die Befehlszeilen-Einführung</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Getting_started/Your_first_website\">Ihre erste Website</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Getting_started/Your_first_website/What_will_your_website_look_like\">Wie wird Ihre Website aussehen?</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Your_first_website/Creating_the_content\">HTML: Erstellen der Inhalte</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Your_first_website/Styling_the_content\">CSS: Gestaltung des Inhalts</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Your_first_website/Adding_interactivity\">JavaScript: Interaktivität hinzufügen</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Your_first_website/Publishing_your_website\">Veröffentlichen Ihrer Website</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Getting_started/Web_standards\">Webstandards</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works\">How the web works</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Web_standards/The_web_standards_model\">Das Modell der Webstandards</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites\">Wie Browser Websites laden</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Getting_started/Soft_skills\">Soziale Kompetenzen</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Getting_started/Soft_skills/Research_and_learning\">Forschung und Lernen</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Soft_skills/Collaboration_and_teamwork\">Zusammenarbeit und Teamarbeit</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Soft_skills/Workflows_and_processes\">Workflows und Prozesse</a></li><li><a href=\"/de/docs/Learn_web_development/Getting_started/Soft_skills/Job_interviews\">Erfolgreich in Vorstellungsgesprächen</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn_web_development/Core\">Kernmodule</a></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/Structuring_content\">Inhalte mit HTML strukturieren</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax\">Grundlegende HTML-Syntax</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata\">Was befindet sich im Kopf? Metadaten einer Webseite</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Headings_and_paragraphs\">Überschriften und Absätze in HTML</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Emphasis_and_importance\">Hervorhebung und Wichtigkeit</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Lists\">Listen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Structuring_documents\">Strukturierung von Dokumenten</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Advanced_text_features\">Erweiterte Textfunktionen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Creating_links\">Erstellen von Links</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Marking_up_a_letter\">Herausforderung: Eine E-Mail korrekt auszeichnen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Structuring_a_page_of_content\">Herausforderung: Strukturierung einer Inhaltsseite</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/HTML_images\">HTML-Bilder</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/HTML_video_and_audio\">HTML video und audio</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Mozilla_splash_page\">Herausforderung: Mozilla Splash-Seite</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics\">Grundlagen von HTML-Tabellen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Table_accessibility\">Barrierefreiheit von HTML-Tabellen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Planet_data_table\">Herausforderung: Strukturierung einer Planeten-Datentabelle</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/HTML_forms\">Formulare und Schaltflächen in HTML</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Structuring_content/Debugging_HTML\">Debugging von HTML</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/Styling_basics\">Grundlagen des CSS-Stylings</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/What_is_CSS\">Was ist CSS?</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Getting_started\">Einstieg in CSS</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Styling_a_bio_page\">Herausforderung: Gestaltung einer Biografie-Seite</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Basic_selectors\">Grundlagen der CSS-Selektoren</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Attribute_selectors\">Attribut-Selektoren</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Pseudo_classes_and_elements\">Pseudoklassen und Pseudoelemente</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Combinators\">Kombinatoren</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Box_model\">Das Box-Modell</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Handling_conflicts\">Umgang mit Konflikten</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Values_and_units\">CSS-Werte und -Einheiten</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Sizing\">Größenbestimmung von Elementen in CSS</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Backgrounds_and_borders\">Hintergründe und Rahmen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Overflow\">Überlaufender Inhalt</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Images_media_forms\">Bilder, Medien und Formularelemente</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Tables\">Tabellen stylen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Debugging_CSS\">Debugging CSS</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Fundamental_CSS_comprehension\">Herausforderung: Grundlegendes CSS-Verständnis</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Fancy_letterheaded_paper\">Herausforderung: Erstellung eines ansprechenden Briefpapiers</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Styling_basics/Cool-looking_box\">Herausforderung: Eine cool aussehende Box</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/Text_styling\">CSS-Textgestaltung</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/Text_styling/Fundamentals\">Grundlegendes zur Text- und Schriftgestaltung</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Text_styling/Styling_lists\">Listen gestalten</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Text_styling/Styling_links\">Gestaltung von Links</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Text_styling/Web_fonts\">Webfonts</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Text_styling/Typesetting_a_homepage\">Herausforderung: Setzen einer Startseite für eine Gemeinschaftsschule</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/CSS_layout\">CSS-Layout</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Introduction\">Einführung in CSS-Layout</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Floats\">Floats</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Positioning\">Platzierung</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Flexbox\">Flexbox</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Grids\">CSS-Grid-Layout</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Responsive_Design\">Responsives Design</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Media_queries\">Grundlagen von Media Query</a></li><li><a href=\"/de/docs/Learn_web_development/Core/CSS_layout/Fundamental_Layout_Comprehension\">Herausforderung: Grundlegendes Verständnis von Layouts</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/Scripting\">Dynamisches Scripting mit JavaScript</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/What_is_JavaScript\">Was ist JavaScript?</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/A_first_splash\">Erster Einblick in JavaScript</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/What_went_wrong\">Was ist schiefgelaufen? JavaScript-Fehlerbehebung</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Variables\">Speichern der benötigten Informationen — Variablen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Math\">Grundlegende Mathematik in JavaScript – Zahlen und Operatoren</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Strings\">Umgang mit Text — Zeichenketten in JavaScript</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Useful_string_methods\">Nützliche String-Methoden</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Arrays\">Arrays</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Silly_story_generator\">Herausforderung: Blödsinnige Geschichtengenerator</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Conditionals\">Entscheidungen in Ihrem Code treffen — Konditionalen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Loops\">Code-Schleifen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Functions\">Funktionen — wiederverwendbare Codeblöcke</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Build_your_own_function\">Erstellen Sie Ihre eigene Funktion</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Return_values\">Funktionsrückgabewerte</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Events\">Einführung in Ereignisse</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Event_bubbling\">Ereignis-Bubbling</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Image_gallery\">Herausforderung: Bildergalerie</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Object_basics\">JavaScript-Objektgrundlagen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/DOM_scripting\">Einführung in DOM-Scripting</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Network_requests\">Netzwerkanfragen mit JavaScript</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/JSON\">Arbeiten mit JSON</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Scripting/Debugging_JavaScript\">Debugging JavaScript and handling errors</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries\">JavaScript-Frameworks und -Bibliotheken</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/Introduction\">Einführung in client-seitige Frameworks</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/Main_features\">Hauptmerkmale von Frameworks</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started\">Erste Schritte mit React</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_todo_list_beginning\">Beginn unserer React To-Do-Liste</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_components\">Komponenten in unserer React-App erstellen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_events_state\">React Interaktivität: Events und State</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering\">Reaktivität in React: Bearbeiten, Filtern, bedingtes Rendern</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility\">Barrierefreiheit in React</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Frameworks_libraries/React_resources\">React-Ressourcen</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Core/Accessibility\">Barrierefreiheit</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/What_is_accessibility\">Was ist Barrierefreiheit?</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/Tooling\">Barrierefreiheitstools und unterstützende Technologien</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/HTML\">HTML: Eine gute Grundlage für Barrierefreiheit</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript\">CSS and JavaScript Zugänglichkeitsbest Practices</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/WAI-ARIA_basics\">WAI-ARIA Grundlagen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/Multimedia\">Barrierefreie Multimedia-Inhalte</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/Mobile\">Mobile Accessibility</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Accessibility/Accessibility_troubleshooting\">Herausforderung: Barrierefreiheits-Fehlerbehebung</a></li></ol></details></li><li><a href=\"/de/docs/Learn_web_development/Core/Design_for_developers\">Design für Entwickler:innen</a></li><li><a href=\"/de/docs/Learn_web_development/Core/Version_control\">Versionskontrolle</a></li><li class=\"section\"><a href=\"/de/docs/Learn_web_development/Extensions\">Erweiterungsmodule</a></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects\">Advanced JavaScript objects</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes\">Objektprototypen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming\">Objektorientierte Programmierung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Classes_in_JavaScript\">Klassen in JavaScript</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_building_practice\">Objektbaupraxis</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Adding_bouncing_balls_features\">Herausforderung: Hinzufügen von Funktionen zu unserem hüpfenden Ball-Demo</a></li></ol></details></li><li class=\"toggle\"><details open=\"\"><summary><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs\">Client-seitige Web-APIs</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Introduction\">Einführung in Web-APIs</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Video_and_audio_APIs\">Video- und Audio-APIs</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics\">Zeichnen von Grafiken</a></li><li><em><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage\" aria-current=\"page\">Client-seitiger Speicher</a></em></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs\">Third-party APIs</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Async_JS\">Asynchrones JavaScript</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Async_JS/Introducing\">Einführung in asynchrones JavaScript</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Async_JS/Promises\">Anleitung zur Verwendung von Promises</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Async_JS/Implementing_a_promise-based_API\">Wie man eine Promise-basierte API implementiert</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Async_JS/Introducing_workers\">Einführung in Worker</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Async_JS/Sequencing_animations\">Herausforderung: Animationen sequenzieren</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Forms\">Webformulare — Arbeiten mit Benutzerdaten</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Your_first_form\">Ihr erstes Formular</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form\">Wie man ein Webformular strukturiert</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls\">Grundlegende native Formularsteuerungen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/HTML5_input_types\">Die HTML5-Eingabetypen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Other_form_controls\">Andere Formularelemente</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Styling_web_forms\">Styling von Webformularen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Advanced_form_styling\">Fortgeschrittenes Formular-Styling</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/UI_pseudo-classes\">UI-Pseudoklassen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Form_validation\">Client-seitige Formularvalidierung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data\">Senden von Formulardaten</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_tools\">Verständnis für clientseitige Tools</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_tools/Overview\">Überblick über Client-seitige Tools</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_tools/Package_management\">Grundlagen des Paketmanagements</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_tools/Introducing_complete_toolchain\">Einführung in eine vollständige Werkzeugkette</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Client-side_tools/Deployment\">Bereitstellung unserer App</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Server-side\">Serverseitige Programmierung</a></summary><ol><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps\">Erste Schritte auf der Serverseite</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction\">Einführung in die Server-Seite</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview\">Überblick über Client-Server</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Web_frameworks\">Server-seitige Web-Frameworks</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security\">Website-Sicherheit</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django\">Django Web-Framework (Python)</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Introduction\">Einführung in Django</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/development_environment\">Einrichten einer Django-Entwicklungsumgebung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Tutorial_local_library_website\">Django Tutorial: Die Website der lokalen Bibliothek</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website\">Django-Tutorial Teil 2: Erstellen einer Skelett-Website</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Models\">Django Tutorial Teil 3: Verwenden von Modellen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Admin_site\">Django Tutorial Teil 4: Die Django Admin-Seite</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Home_page\">Django Tutorial Teil 5: Erstellen unserer Homepage</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Generic_views\">Django Tutorial Teil 6: Generische Listen- und Detailansichten</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Sessions\">Django-Tutorial Teil 7: Sitzungs-Framework</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Authentication\">Django-Tutorial Teil 8: Benutzer-Authentifizierung und -Berechtigungen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Forms\">Django Tutorial Teil 9: Arbeiten mit Formularen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Testing\">Django Tutorial Teil 10: Testen einer Django-Webanwendung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/Deployment\">Django-Tutorial Teil 11: Bereitstellung von Django für die Produktion</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/web_application_security\">Django Webanwendungssicherheit</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Django/django_assessment_blog\">Bewertung: DIY Django Mini-Blog</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs\">Express Web-Framework (Node.js)</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction\">Einführung in Express/Node</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/development_environment\">Einrichten einer Node-Entwicklungsumgebung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Tutorial_local_library_website\">Express Tutorial: Die Website der lokalen Bibliothek</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/skeleton_website\">Express-Tutorial Teil 2: Erstellen einer Skelett-Website</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/mongoose\">Express-Tutorial Teil 3: Verwendung einer Datenbank (mit Mongoose)</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes\">Express Tutorial Teil 4: Routen und Controller</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Displaying_data\">Express Tutorial Teil 5: Bibliotheksdaten anzeigen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/forms\">Express Tutorial Teil 6: Arbeiten mit Formularen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/deployment\">Express Tutorial Teil 7: Bereitstellung im Produktionsumfeld</a></li></ol></details></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Performance\">Web-Performance</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/why_web_performance\">Das \"Warum\" der Web-Performance</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/What_is_web_performance\">Was ist Web-Performance?</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/Perceived_performance\">Wahrgenommene Leistung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/Measuring_performance\">Leistungsmessung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/Multimedia\">Multimedia: Bilder</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/video\">Multimedia: video</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/JavaScript\">JavaScript-Leistungsoptimierung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/HTML\">HTML-Performance-Optimierung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/CSS\">CSS-Leistungsoptimierung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Performance/business_case_for_performance\">Der geschäftliche Nutzen der Web-Performance</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Extensions/Testing\">Tests</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Extensions/Testing/Introduction\">Einführung in das Cross-Browser-Testing</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Testing/Testing_strategies\">Strategien zur Durchführung von Tests</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Testing/HTML_and_CSS\">Umgang mit häufigen HTML- und CSS-Problemen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Testing/Feature_detection\">Implementierung der Funktionsprüfung</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Testing/Automated_testing\">Einführung in automatisiertes Testen</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Testing/Your_own_automation_environment\">Einrichtung Ihrer eigenen Testautomatisierungsumgebung</a></li></ol></details></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Transform_animate\">CSS transformieren und animieren</a></li><li><a href=\"/de/docs/Learn_web_development/Extensions/Security_privacy\">Sicherheit und Datenschutz</a></li><li class=\"section\">Weitere Ressourcen</li><li class=\"toggle\"><details><summary><a href=\"/de/docs/Learn_web_development/Howto\">Häufige Probleme lösen</a></summary><ol><li><a href=\"/de/docs/Learn_web_development/Howto/Solve_HTML_problems\">Häufige HTML-Probleme lösen</a></li><li><a href=\"/de/docs/Learn_web_development/Howto/Solve_CSS_problems\">Häufige CSS-Probleme lösen</a></li><li><a href=\"/de/docs/Learn_web_development/Howto/Solve_JavaScript_problems\">Häufige JavaScript-Probleme lösen</a></li><li><a href=\"/de/docs/Learn_web_development/Howto/Web_mechanics\">Webmechanik</a></li><li><a href=\"/de/docs/Learn_web_development/Howto/Tools_and_setup\">Tools und Einrichtung</a></li><li><a href=\"/de/docs/Learn_web_development/Howto/Design_and_accessibility\">Design und Barrierefreiheit</a></li></ol></details></li><li><a href=\"/de/docs/Learn_web_development/About\">Über</a></li><li><a href=\"/de/docs/Learn_web_development/Educators\">Ressourcen für Lehrkräfte</a></li><li><a href=\"/de/docs/Learn_web_development/Changelog\">Änderungsprotokoll</a></li></ol>","source":{"folder":"de/learn_web_development/extensions/client-side_apis/client-side_storage","github_url":"https://github.com/mdn/translated-content-de/blob/main/files/de/learn_web_development/extensions/client-side_apis/client-side_storage/index.md","last_commit_url":"https://github.com/mdn/translated-content-de/commit/452fe502cfb4c9a91c346af17370ecfb6a8bd17e","filename":"index.md"},"summary":"Moderne Webbrowser unterstützen eine Vielzahl von Möglichkeiten, wie Websites Daten auf dem Rechner des Nutzers speichern und bei Bedarf abrufen können – mit der Erlaubnis des Nutzers. Dies ermöglicht Ihnen, Daten für die langfristige Speicherung zu speichern, Seiten oder Dokumente für die Offline-Nutzung zu sichern, nutzerspezifische Einstellungen für Ihre Website zu behalten und mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Techniken.","title":"Client-seitiger Speicher","toc":[{"text":"Client-seitiger Speicher?","id":"client-seitiger_speicher"},{"text":"Speichern einfacher Daten – Web Storage","id":"speichern_einfacher_daten_–_web_storage"},{"text":"Speichern komplexer Daten – IndexedDB","id":"speichern_komplexer_daten_–_indexeddb"},{"text":"Offline-Asset-Speicherung","id":"offline-asset-speicherung"},{"text":"Zusammenfassung","id":"zusammenfassung"},{"text":"Siehe auch","id":"siehe_auch"}],"pageType":"learn-module-chapter"}}</script></body></html>