CINXE.COM
Client-side storage - Webentwicklung lernen | 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-side storage - Webentwicklung lernen | MDN</title><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="en"/><link rel="alternate" title="Almacenamiento del lado cliente" href="https://developer.mozilla.org/es/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="es"/><link rel="alternate" title="Stockage côté client" href="https://developer.mozilla.org/fr/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="fr"/><link rel="alternate" title="クライアント側ストレージ" href="https://developer.mozilla.org/ja/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="ja"/><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/pt-BR/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="pt"/><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="ru"/><link rel="alternate" title="客户端存储" href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" hrefLang="zh"/><link rel="alternate" title="Client-side storage" href="https://developer.mozilla.org/de/docs/Learn/JavaScript/Client-side_web_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="robots" content="noindex, follow"/><meta name="description" content="Moderne Webbrowser unterstützen verschiedene Methoden, um Daten auf dem Computer des Benutzers zu speichern – mit Zustimmung des Benutzers – und diese bei Bedarf wieder abzurufen. Dies ermöglicht es Ihnen, Daten für die langfristige Speicherung zu behalten, Websites oder Dokumente für die Offline-Nutzung zu speichern, benutzerspezifische Einstellungen für Ihre Website beizubehalten und vieles mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Methoden."/><meta property="og:url" content="https://developer.mozilla.org/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage"/><meta property="og:title" content="Client-side storage - Webentwicklung lernen | MDN"/><meta property="og:type" content="website"/><meta property="og:locale" content="de"/><meta property="og:description" content="Moderne Webbrowser unterstützen verschiedene Methoden, um Daten auf dem Computer des Benutzers zu speichern – mit Zustimmung des Benutzers – und diese bei Bedarf wieder abzurufen. Dies ermöglicht es Ihnen, Daten für die langfristige Speicherung zu behalten, Websites oder Dokumente für die Offline-Nutzung zu speichern, benutzerspezifische Einstellungen für Ihre Website beizubehalten und vieles mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Methoden."/><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/JavaScript/Client-side_web_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.5e889624.js"></script><link href="/static/css/main.26c64ea7.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-javascript 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="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="guides-button" class="top-level-entry menu-toggle" aria-controls="guides-menu" aria-expanded="false">Guides</button><a href="/de/docs/Learn" class="top-level-entry">Guides</a><ul id="guides-menu" class="submenu guides hidden inline-submenu-lg" aria-labelledby="guides-button"><li class="apis-link-container mobile-only "><a href="/de/docs/Learn" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="apis-link-container desktop-only "><a href="/de/docs/Learn" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="html-link-container "><a href="/de/docs/Learn/HTML" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Learn to structure web content with HTML</p></div></a></li><li class="css-link-container "><a href="/de/docs/Learn/CSS" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Learn to style content using CSS</p></div></a></li><li class="javascript-link-container "><a href="/de/docs/Learn/JavaScript" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">Learn to run scripts in the browser</p></div></a></li><li class=" "><a href="/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">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%2FJavaScript%2FClient-side_web_APIs%2FClient-side_storage" class="login-link" rel="nofollow">Log in</a></li><li><a href="/users/fxa/login/authenticate/?next=%2Fde%2Fdocs%2FLearn%2FJavaScript%2FClient-side_web_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" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Webentwicklung lernen</span></a><meta property="position" content="1"/></li><li property="itemListElement" typeof="ListItem"><a href="/de/docs/Learn/JavaScript" class="breadcrumb" property="item" typeof="WebPage"><span property="name">JavaScript — Dynamisches clientseitiges Scripting</span></a><meta property="position" content="2"/></li><li property="itemListElement" typeof="ListItem"><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Client-Side-Web-APIs</span></a><meta property="position" content="3"/></li><li property="itemListElement" typeof="ListItem"><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" class="breadcrumb-current-page" property="item" typeof="WebPage"><span property="name">Client-side storage</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/JavaScript/Client-side_web_APIs/Client-side_storage" class="button submenu-item"><span>English (US)</span></a></li><li class=" "><a data-locale="es" href="/es/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" class="button submenu-item"><span>Español</span></a></li><li class=" "><a data-locale="fr" href="/fr/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" class="button submenu-item"><span>Français</span></a></li><li class=" "><a data-locale="ja" href="/ja/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" class="button submenu-item"><span>日本語</span></a></li><li class=" "><a data-locale="pt-BR" href="/pt-BR/docs/Learn/JavaScript/Client-side_web_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/JavaScript/Client-side_web_APIs/Client-side_storage" class="button submenu-item"><span>Русский</span></a></li><li class=" "><a data-locale="zh-CN" href="/zh-CN/docs/Learn/JavaScript/Client-side_web_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" data-macro="LearnSidebar"><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-seitige_speicherung">Client-seitige Speicherung?</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speicherung_einfacher_daten_—_web_storage">Speicherung einfacher Daten — Web Storage</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speicherung_komplexer_daten_—_indexeddb">Speicherung komplexer Daten — IndexedDB</a></li><li class="document-toc-item "><a class="document-toc-link" href="#offline-speicherung_von_ressourcen">Offline-Speicherung von Ressourcen</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/Getting_started_with_the_web">Komplette Anfänger beginnen hier!</a></li><li><details><summary>Erste Schritte mit dem Web</summary><ol><li><a href="/de/docs/Learn/Getting_started_with_the_web">Einführung ins Web</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/Installing_basic_software">Installation von grundlegender Software</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Wie wird Ihre Website aussehen?</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Umgang mit Dateien</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/HTML_basics">HTML-Grundlagen</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/CSS_basics">CSS-Grundlagen</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript-Grundlagen</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Veröffentlichung Ihrer Website</a></li><li><a href="/de/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Wie das Web funktioniert</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/HTML">HTML — Strukturierung des Webs</a></li><li><details><summary>Einführung in HTML</summary><ol><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML">Einführung in HTML</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Erste Schritte mit HTML</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">Was ist im Kopfbereich? Metadaten in HTML</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">Grundlagen des HTML-Textes</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Erstellen von Hyperlinks</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Erweiterte Textformatierung</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Struktur eines Dokuments und einer Website</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Markierung eines Briefes</a></li><li><a href="/de/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Die Strukturierung einer Seite mit Inhalt</a></li></ol></details></li><li><details><summary>Multimedia und Einbettung</summary><ol><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding">Multimedia und Einbettung</a></li><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Bilder in HTML</a></li><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video- und Audioinhalte</a></li><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">Von Objekt zu iframe — andere Einbettungstechnologien</a></li><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Vektorgrafiken zum Web hinzufügen</a></li><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive Images</a></li><li><a href="/de/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla Splash-Seite</a></li></ol></details></li><li><details><summary>HTML-Tabellen</summary><ol><li><a href="/de/docs/Learn/HTML/Tables">HTML-Tabellen</a></li><li><a href="/de/docs/Learn/HTML/Tables/Basics">HTML Table Grundlagen</a></li><li><a href="/de/docs/Learn/HTML/Tables/Advanced">Erweiterte Funktionen und Barrierefreiheit von HTML-Tabellen</a></li><li><a href="/de/docs/Learn/HTML/Tables/Structuring_planet_data">Strukturierung von Planeten-Daten</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/CSS">CSS — Gestaltung des Webs</a></li><li><details><summary>CSS erste Schritte</summary><ol><li><a href="/de/docs/Learn/CSS/First_steps">Erste Schritte mit CSS</a></li><li><a href="/de/docs/Learn/CSS/First_steps/What_is_CSS">Was ist CSS?</a></li><li><a href="/de/docs/Learn/CSS/First_steps/Getting_started">Einstieg in CSS</a></li><li><a href="/de/docs/Learn/CSS/First_steps/How_CSS_is_structured">Wie CSS strukturiert ist</a></li><li><a href="/de/docs/Learn/CSS/First_steps/How_CSS_works">Wie CSS funktioniert</a></li><li><a href="/de/docs/Learn/CSS/First_steps/Styling_a_biography_page">Eine Biografieseite stylen</a></li></ol></details></li><li><details><summary>CSS-Bausteine</summary><ol><li><a href="/de/docs/Learn/CSS/Building_blocks">CSS-Grundbausteine</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Selectors">CSS-Selektoren</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Typ-, Klassen- und ID-Selektoren</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attributselektoren</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-Klassen und Pseudo-Elemente</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Kombinatoren</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Kaskade, Spezifität und Vererbung</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Cascade_layers">Kaskadenschichten</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/The_box_model">Das Boxmodell</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Hintergründe und Rahmen</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Umgang mit unterschiedlichen Textausrichtungen</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Overflowing_content">Überlaufender Inhalt</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Values_and_units">CSS-Werte und Einheiten</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Größe von Elementen in CSS</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Bilder, Medien und Formularelemente</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Styling_tables">Tabellen stylen</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Advanced_styling_effects">Erweiterte Styling-Effekte</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Organizing">Organisieren Ihres CSS</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Fundamental_CSS_comprehension">Grundlegendes CSS-Verständnis</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/Creating_fancy_letterheaded_paper">Erstellen von stilvollem Briefpapier</a></li><li><a href="/de/docs/Learn/CSS/Building_blocks/A_cool_looking_box">Eine cool aussehende Box</a></li></ol></details></li><li><details><summary>Textgestaltung</summary><ol><li><a href="/de/docs/Learn/CSS/Styling_text">CSS Textgestaltung</a></li><li><a href="/de/docs/Learn/CSS/Styling_text/Fundamentals">Grundlegende Text- und Schriftgestaltung</a></li><li><a href="/de/docs/Learn/CSS/Styling_text/Styling_lists">Listen stilisieren</a></li><li><a href="/de/docs/Learn/CSS/Styling_text/Styling_links">Styling von Links</a></li><li><a href="/de/docs/Learn/CSS/Styling_text/Web_fonts">Web-Fonts</a></li><li><a href="/de/docs/Learn/CSS/Styling_text/Typesetting_a_homepage">Setzen einer Community-Schul-Startseite</a></li></ol></details></li><li><details><summary>CSS-Layout</summary><ol><li><a href="/de/docs/Learn/CSS/CSS_layout">CSS-Layout</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Introduction">Einführung in CSS Layout</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Normal_Flow">Normaler Fluss</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Grids">Raster</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Positioning">Positioning</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Mehrspaltiges Layout</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Responsive_Design">Responsives Design</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Media_queries">Einsteigerleitfaden für Media Queries</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Legacy-Layout-Methoden</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Unterstützung älterer Browser</a></li><li><a href="/de/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Grundlegendes Verständnis von Layouts</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/JavaScript">JavaScript — Dynamisches clientseitiges Skripting</a></li><li><details><summary>JavaScript erste Schritte</summary><ol><li><a href="/de/docs/Learn/JavaScript/First_steps">JavaScript erste Schritte</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/What_is_JavaScript">Was ist JavaScript?</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/A_first_splash">Ein erster Sprung in JavaScript</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/What_went_wrong">Was ist schiefgelaufen? JavaScript-Fehlerbehebung</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/Variables">Speichern der benötigten Informationen — Variablen</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/Math">Grundlegende Mathematik in JavaScript – Zahlen und Operatoren</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/Strings">Umgang mit Text — Strings in JavaScript</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/Useful_string_methods">Nützliche String-Methoden</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li><li><a href="/de/docs/Learn/JavaScript/First_steps/Silly_story_generator">Silly Story Generator</a></li></ol></details></li><li><details><summary>JavaScript-Bausteine</summary><ol><li><a href="/de/docs/Learn/JavaScript/Building_blocks">JavaScript-Bausteine</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/conditionals">Entscheidungen in Ihrem Code treffen — Bedingte Anweisungen</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Looping_code">Schleifen-Code</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Functions">Funktionen — wiederverwendbare Codeblöcke</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Erstellen Sie Ihre eigene Funktion</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Return_values">Funktionsrückgabewerte</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Events">Einführung in Ereignisse</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Event_bubbling">Event bubbling</a></li><li><a href="/de/docs/Learn/JavaScript/Building_blocks/Image_gallery">Bildgalerie</a></li></ol></details></li><li><details><summary>Einführung in JavaScript-Objekte</summary><ol><li><a href="/de/docs/Learn/JavaScript/Objects">Einführung in JavaScript-Objekte</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/Basics">JavaScript Objekt Grundlagen</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/Object_prototypes">Objektprototypen</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/Object-oriented_programming">Objektorientierte Programmierung</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/Classes_in_JavaScript">Klassen in JavaScript</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/JSON">Arbeiten mit JSON</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/Object_building_practice">Objekt-Baupraxis</a></li><li><a href="/de/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Hinzufügen von Funktionen zu unserem hüpfenden Kugeln-Demo</a></li></ol></details></li><li><details><summary>Asynchrones JavaScript</summary><ol><li><a href="/de/docs/Learn/JavaScript/Asynchronous">Asynchrones JavaScript</a></li><li><a href="/de/docs/Learn/JavaScript/Asynchronous/Introducing">Einführung in asynchrones JavaScript</a></li><li><a href="/de/docs/Learn/JavaScript/Asynchronous/Promises">Anleitung zur Verwendung von Promises</a></li><li><a href="/de/docs/Learn/JavaScript/Asynchronous/Implementing_a_promise-based_API">Anleitung zur Implementierung einer Promise-basierten API</a></li><li><a href="/de/docs/Learn/JavaScript/Asynchronous/Introducing_workers">Einführung in Workers</a></li><li><a href="/de/docs/Learn/JavaScript/Asynchronous/Sequencing_animations">Sequenzierung von Animationen</a></li></ol></details></li><li><details open=""><summary>Client-seitige Web-APIs</summary><ol><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs">Client-Side-Web-APIs</a></li><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Einführung in Web-APIs</a></li><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Abrufen von Daten vom Server</a></li><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third-party APIs</a></li><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Grafiken zeichnen</a></li><li><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video- und Audio-APIs</a></li><li><em><a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage" aria-current="page">Client-side storage</a></em></li></ol></details></li><li class="section"><a href="/de/docs/Learn/Forms">Webformulare — Arbeiten mit Benutzerdaten</a></li><li><details><summary>Grundlagen der Webformulare</summary><ol><li><a href="/de/docs/Learn/Forms">Bausteine für Webformulare</a></li><li><a href="/de/docs/Learn/Forms/Your_first_form">Ihr erstes Formular</a></li><li><a href="/de/docs/Learn/Forms/How_to_structure_a_web_form">Wie Sie ein Webformular strukturieren</a></li><li><a href="/de/docs/Learn/Forms/Basic_native_form_controls">Basis-Native Formularelemente</a></li><li><a href="/de/docs/Learn/Forms/HTML5_input_types">Die HTML5 input Typen</a></li><li><a href="/de/docs/Learn/Forms/Other_form_controls">Andere Formularelemente</a></li><li><a href="/de/docs/Learn/Forms/Styling_web_forms">Styling von Webformularen</a></li><li><a href="/de/docs/Learn/Forms/Advanced_form_styling">Erweiterte Formular-Stilgestaltung</a></li><li><a href="/de/docs/Learn/Forms/UI_pseudo-classes">UI-Pseudo-Klassen</a></li><li><a href="/de/docs/Learn/Forms/Form_validation">Client-seitige Formularvalidierung</a></li><li><a href="/de/docs/Learn/Forms/Sending_and_retrieving_form_data">Senden von Formulardaten</a></li></ol></details></li><li><details><summary>Erweiterte Techniken für Webformulare</summary><ol><li><a href="/de/docs/Learn/Forms/How_to_build_custom_form_controls">Anleitung zur Erstellung benutzerdefinierter Formularelemente</a></li><li><a href="/de/docs/Learn/Forms/Sending_forms_through_JavaScript">Versenden von Formularen über JavaScript</a></li><li><a href="/de/docs/Learn/Forms/Property_compatibility_table_for_form_controls">CSS-Eigenschaftskompatibilitätstabelle für Formularelemente</a></li><li><a href="/de/docs/Learn/Forms/HTML_forms_in_legacy_browsers">HTML-Formulare in älteren Browsern</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/Accessibility">Barrierefreiheit — Das Web für alle nutzbar machen</a></li><li><details><summary>Barrierefreiheitsleitfäden</summary><ol><li><a href="/de/docs/Learn/Accessibility">Barrierefreiheit</a></li><li><a href="/de/docs/Learn/Accessibility/What_is_accessibility">Was ist Barrierefreiheit?</a></li><li><a href="/de/docs/Learn/Accessibility/HTML">HTML: Eine gute Grundlage für Barrierefreiheit</a></li><li><a href="/de/docs/Learn/Accessibility/CSS_and_JavaScript">CSS und JavaScript: Barrierefreiheits-Best Practices</a></li><li><a href="/de/docs/Learn/Accessibility/WAI-ARIA_basics">Grundlagen von WAI-ARIA</a></li><li><a href="/de/docs/Learn/Accessibility/Multimedia">Barrierefreie Multimedia</a></li><li><a href="/de/docs/Learn/Accessibility/Mobile">Barrierefreiheit auf Mobilgeräten</a></li><li><a href="/de/docs/Learn/Accessibility/Accessibility_troubleshooting">Bewertung: Barrierefreiheits-Troubleshooting</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/Performance">Leistung — Websites schnell und reaktionsschnell machen</a></li><li><details><summary>Leitfäden zur Leistung</summary><ol><li><a href="/de/docs/Learn/Performance">Webleistung</a></li><li><a href="/de/docs/Learn/Performance/why_web_performance">Der 'Warum' der Web-Performance</a></li><li><a href="/de/docs/Learn/Performance/What_is_web_performance">Was ist Web-Performance?</a></li><li><a href="/de/docs/Learn/Performance/Perceived_performance">Wahrgenommene Leistung</a></li><li><a href="/de/docs/Learn/Performance/Measuring_performance">Messung der Performance</a></li><li><a href="/de/docs/Learn/Performance/Multimedia">Multimedia: Bilder</a></li><li><a href="/de/docs/Learn/Performance/video">Multimedia: Video</a></li><li><a href="/de/docs/Learn/Performance/JavaScript">JavaScript-Leistungsoptimierung</a></li><li><a href="/de/docs/Learn/Performance/HTML">HTML-Leistungsoptimierung</a></li><li><a href="/de/docs/Learn/Performance/CSS">CSS-Leistungsoptimierung</a></li><li><a href="/de/docs/Learn/Performance/business_case_for_performance">Der geschäftliche Nutzen von Web-Performance</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/MathML">MathML — Schreiben von Mathematik mit MathML</a></li><li><details><summary>MathML erste Schritte</summary><ol><li><a href="/de/docs/Learn/MathML/First_steps">Erste Schritte mit MathML</a></li><li><a href="/de/docs/Learn/MathML/First_steps/Getting_started">Erste Schritte mit MathML</a></li><li><a href="/de/docs/Learn/MathML/First_steps/Text_containers">MathML Text-Container</a></li><li><a href="/de/docs/Learn/MathML/First_steps/Fractions_and_roots">MathML-Brüche und -Wurzeln</a></li><li><a href="/de/docs/Learn/MathML/First_steps/Scripts">MathML gescriptete Elemente</a></li><li><a href="/de/docs/Learn/MathML/First_steps/Tables">MathML Tabellen</a></li><li><a href="/de/docs/Learn/MathML/First_steps/Three_famous_mathematical_formulas">Drei berühmte mathematische Formeln</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/../Games">Spiele — Entwicklung von Spielen für das Web</a></li><li><details><summary>Anleitungen und Tutorials</summary><ol><li><a href="/de/docs/Games/Introduction">Einführung in die Spieleentwicklung für das Web</a></li><li><a href="/de/docs/Games/Techniques">Techniken für die Spieleentwicklung</a></li><li><a href="/de/docs/Games/Tutorials">Tutorials</a></li><li><a href="/de/docs/Games/Publishing_games">Publishing Games</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/Tools_and_testing">Werkzeuge und Tests</a></li><li><details><summary>Client-seitige Webentwicklungstools</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools">Verständnis von Client-seitigen Webentwicklungstools</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview">Übersicht über clientseitige Werkzeuge</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line">Crashkurs zur Kommandozeile</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management">Grundlagen des Paketmanagements</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Introducing_complete_toolchain">Einführung in eine vollständige Toolchain</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Deployment">Bereitstellung unserer App</a></li></ol></details></li><li><details><summary>Einführung in client-seitige Frameworks</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">Einführung in client-seitige Frameworks</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">Hauptmerkmale von Frameworks</a></li></ol></details></li><li><details><summary>React</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">Erste Schritte mit React</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">Beginn unserer React-Task-Liste</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">Komponentisieren unserer React-App</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">React-Interaktivität: Ereignisse und Status</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">React Interaktivität: Bearbeiten, Filtern, bedingtes Rendering</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">Accessibility in React</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">React-Ressourcen</a></li></ol></details></li><li><details><summary>Ember</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">Einstieg in Ember</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">Ember App-Struktur und Komponentisierung</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">Ember-Interaktivität: Events, Klassen und Zustand</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">Ember Interaktivität: Footer-Funktionalität, bedingtes Rendering</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">Routing in Ember</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">Ember-Ressourcen und Fehlerbehebung</a></li></ol></details></li><li><details><summary>Vue</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">Einstieg in Vue</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">Erstellen unserer ersten Vue-Komponente</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">Rendering einer Liste von Vue-Komponenten</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">Hinzufügen eines neuen Todo-Formulars: Vue-Ereignisse, Methoden und Modelle</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">Styling von Vue-Komponenten mit CSS</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">Verwendung von Vue computed properties</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">Vue bedingte Darstellung: Bearbeitung bestehender Todos</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">Vue-Refs und Lifecycle-Methoden zur Fokusverwaltung</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">Vue-Ressourcen</a></li></ol></details></li><li><details><summary>Svelte</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_getting_started">Erste Schritte mit Svelte</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning">Starten unserer Svelte-Tasklisten-App</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props">Dynamisches Verhalten in Svelte: Arbeiten mit Variablen und Props</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components">Komponentisierung unserer Svelte-App</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility">Fortgeschrittenes Svelte: Reaktivität, Lebenszyklus, Barrierefreiheit</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores">Arbeiten mit Svelte Stores</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript">TypeScript-Unterstützung in Svelte</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next">Bereitstellung und nächste Schritte</a></li></ol></details></li><li><details><summary>Angular</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_getting_started">Erste Schritte mit Angular</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_todo_list_beginning">Anfang unserer Angular-To-Do-Liste-App</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_styling">Styling unserer Angular-Anwendung</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_item_component">Erstellen einer Item-Komponente</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_filtering">Filtern unserer To-Do-Elemente</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_building">Building Angular applications and further resources</a></li></ol></details></li><li><details><summary>Git und GitHub</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/GitHub">Git und GitHub</a></li></ol></details></li><li><details><summary>Cross-Browser-Tests</summary><ol><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing">Cross-Browser-Testing</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">Einführung in das Cross-Browser-Testing</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">Strategien zur Durchführung von Tests</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">Umgang mit häufigen HTML- und CSS-Problemen</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Umgang mit häufigen JavaScript-Problemen</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Umgang mit häufigen Problemen der Barrierefreiheit</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">Implementierung von Feature-Erkennung</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">Einführung in automatisiertes Testen</a></li><li><a href="/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Einrichten Ihrer eigenen Testautomatisierungsumgebung</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/Server-side">Server-seitige Webprogrammierung</a></li><li><details><summary>Erste Schritte</summary><ol><li><a href="/de/docs/Learn/Server-side/First_steps">Server-seitige Website-Programmierung: Erste Schritte</a></li><li><a href="/de/docs/Learn/Server-side/First_steps/Introduction">Einführung in die serverseitige Programmierung</a></li><li><a href="/de/docs/Learn/Server-side/First_steps/Client-Server_overview">Überblick über Client-Server</a></li><li><a href="/de/docs/Learn/Server-side/First_steps/Web_frameworks">Serverseitige Web-Frameworks</a></li><li><a href="/de/docs/Learn/Server-side/First_steps/Website_security">Website-Sicherheit</a></li></ol></details></li><li><details><summary>Django Web-Framework (Python)</summary><ol><li><a href="/de/docs/Learn/Server-side/Django">Django Web Framework (Python)</a></li><li><a href="/de/docs/Learn/Server-side/Django/Introduction">Einführung in Django</a></li><li><a href="/de/docs/Learn/Server-side/Django/development_environment">Einrichten einer Django-Entwicklungsumgebung</a></li><li><a href="/de/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django-Tutorial: Die Local Library Website</a></li><li><a href="/de/docs/Learn/Server-side/Django/skeleton_website">Django-Tutorial Teil 2: Erstellung einer Skelett-Website</a></li><li><a href="/de/docs/Learn/Server-side/Django/Models">Django-Tutorial Teil 3: Verwenden von Modellen</a></li><li><a href="/de/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Teil 4: Django Admin-Seite</a></li><li><a href="/de/docs/Learn/Server-side/Django/Home_page">Django-Tutorial Teil 5: Erstellen unserer Startseite</a></li><li><a href="/de/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Teil 6: Generische Listen- und Detailansichten</a></li><li><a href="/de/docs/Learn/Server-side/Django/Sessions">Django-Tutorial Teil 7: Sessions-Framework</a></li><li><a href="/de/docs/Learn/Server-side/Django/Authentication">Django-Tutorial Teil 8: Benutzer-Authentifizierung und Berechtigungen</a></li><li><a href="/de/docs/Learn/Server-side/Django/Forms">Django Tutorial Teil 9: Arbeiten mit Formularen</a></li><li><a href="/de/docs/Learn/Server-side/Django/Testing">Django Tutorial Teil 10: Testen einer Django-Webanwendung</a></li><li><a href="/de/docs/Learn/Server-side/Django/Deployment">Django-Tutorial Teil 11: Django in Produktion bereitstellen</a></li><li><a href="/de/docs/Learn/Server-side/Django/web_application_security">Django-Webanwendungssicherheit</a></li><li><a href="/de/docs/Learn/Server-side/Django/django_assessment_blog">Bewertung: DIY Django Mini-Blog</a></li></ol></details></li><li><details><summary>Express Web-Framework (Node.js/JavaScript)</summary><ol><li><a href="/de/docs/Learn/Server-side/Express_Nodejs">Express-Webframework (Node.js/JavaScript)</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/Introduction">Einführung in Express/Node</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/development_environment">Einrichtung einer Node-Entwicklungsumgebung</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express-Tutorial: Die Website der lokalen Bibliothek</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Teil 2: Erstellung einer Grundstruktur für eine Website</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Teil 3: Verwendung einer Datenbank (mit Mongoose)</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Teil 4: Routen und Controller</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Teil 5: Bibliotheksdaten anzeigen</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Teil 6: Arbeiten mit Formularen</a></li><li><a href="/de/docs/Learn/Server-side/Express_Nodejs/deployment">Express-Tutorial Teil 7: Bereitstellung für die Produktion</a></li></ol></details></li><li class="section"><a href="/de/docs/Learn/Common_questions">Weitere Ressourcen</a></li><li><details><summary>Häufige Fragen</summary><ol><li><a href="/de/docs/Learn/Common_questions">Häufige Fragen</a></li><li><a href="/de/docs/Learn/HTML/Howto">HTML verwenden, um häufige Probleme zu lösen</a></li><li><a href="/de/docs/Learn/CSS/Howto">CSS verwenden, um häufige Probleme zu lösen</a></li><li><a href="/de/docs/Learn/JavaScript/Howto">Lösen Sie häufige Probleme in Ihrem JavaScript-Code</a></li><li><a href="/de/docs/Learn/Common_questions/Web_mechanics">Web-Mechanik</a></li><li><a href="/de/docs/Learn/Common_questions/Tools_and_setup">Tools und Einrichtung</a></li><li><a href="/de/docs/Learn/Common_questions/Design_and_accessibility">Design und Barrierefreiheit</a></li></ol></details></li></ol></div></div><section class="place side"></section></nav></aside><div class="toc-container"><aside class="toc"><nav><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In diesem Artikel</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#client-seitige_speicherung">Client-seitige Speicherung?</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speicherung_einfacher_daten_—_web_storage">Speicherung einfacher Daten — Web Storage</a></li><li class="document-toc-item "><a class="document-toc-link" href="#speicherung_komplexer_daten_—_indexeddb">Speicherung komplexer Daten — IndexedDB</a></li><li class="document-toc-item "><a class="document-toc-link" href="#offline-speicherung_von_ressourcen">Offline-Speicherung von Ressourcen</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-side storage</h1></header><div class="section-content"><ul class="prev-next"> <li><a class="button secondary" href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs"><span class="button-wrap"> Zurück </span></a></li> <li><a class="button secondary" href="/de/docs/Learn/JavaScript/Client-side_web_APIs"><span class="button-wrap"> Übersicht: Client-Side-Web-APIs</span></a></li> </ul> <p>Moderne Webbrowser unterstützen verschiedene Methoden, um Daten auf dem Computer des Benutzers zu speichern – mit Zustimmung des Benutzers – und diese bei Bedarf wieder abzurufen. Dies ermöglicht es Ihnen, Daten für die langfristige Speicherung zu behalten, Websites oder Dokumente für die Offline-Nutzung zu speichern, benutzerspezifische Einstellungen für Ihre Website beizubehalten und vieles mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Methoden.</p> <figure class="table-container"><table> <tbody> <tr> <th scope="row">Voraussetzungen:</th> <td> JavaScript-Grundlagen (siehe <a href="/de/docs/Learn/JavaScript/First_steps">Erste Schritte</a>, <a href="/de/docs/Learn/JavaScript/Building_blocks">Bausteine</a>, <a href="/de/docs/Learn/JavaScript/Objects">JavaScript-Objekte</a>), die <a href="/de/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Grundlagen der Client-seitigen APIs</a> </td> </tr> <tr> <th scope="row">Ziel:</th> <td>Erlernen, wie man client-seitige Speicher-APIs verwendet, um Anwendungsdaten zu speichern.</td> </tr> </tbody> </table></figure></div><section aria-labelledby="client-seitige_speicherung"><h2 id="client-seitige_speicherung"><a href="#client-seitige_speicherung">Client-seitige Speicherung?</a></h2><div class="section-content"><p>Andernorts im MDN-Lernbereich haben wir über den Unterschied zwischen <a href="/de/docs/Learn/Server-side/First_steps/Client-Server_overview#static_sites">statischen Websites</a> und <a href="/de/docs/Learn/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 mit Hilfe einer Art Datenbank (serverseitige Speicherung) und führen <a href="/de/docs/Learn/Server-side">serverseitigen</a> Code aus, um benötigte Daten abzurufen, in statische Seitentemplates einzufügen und das resultierende HTML an den Client zu senden, um es im Browser des Benutzers anzuzeigen.</p> <p>Die client-seitige Speicherung funktioniert nach ähnlichen Prinzipien, hat aber andere Anwendungsgebiete. Sie besteht aus JavaScript-APIs, die es ermöglichen, Daten auf dem Client (d. h. auf dem Rechner des Benutzers) zu speichern und bei Bedarf abzurufen. Dies hat viele verschiedene Anwendungen, wie z.B.:</p> <ul> <li>Personalisierung von Seiteneinstellungen (z. B. Anzeige von benutzerdefinierten Widgets, Farbschema oder Schriftgröße).</li> <li>Speichern von vorherigen Aktivitäten auf der Seite (z.B. Speichern des Inhalts eines Warenkorbs aus einer vorherigen Sitzung, Erinnern, ob ein Benutzer zuvor eingeloggt war).</li> <li>Speicherung von Daten und Ressourcen lokal, um eine schnellere (und möglicherweise kostengünstigere) Herunterladung zu ermöglichen oder eine Nutzung ohne Netzwerkverbindung zu erlauben.</li> <li>Speicherung von von Webanwendungen generierten Dokumenten zur Offline-Nutzung</li> </ul> <p>Oft werden client-seitige und serverseitige Speicher gemeinsam verwendet. Beispielsweise könnte man eine Reihe von Musikdateien herunterladen (vielleicht verwendet in einem Webspiel oder einer Musikplayer-Anwendung), diese in einer client-seitigen Datenbank speichern und bei Bedarf abspielen. Der Benutzer müsste 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 Grenzen für die Menge an Daten, die Sie mit client-seitigen Speicher-APIs speichern können (möglicherweise sowohl pro einzelner API als auch kumulativ); das genaue Limit variiert je nach Browser und möglicherweise basierend auf Benutzereinstellungen. Weitere Informationen finden Sie unter <a href="/de/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria">Browser Speicherquoten und Löschkriterien</a>.</p> </div></div></section><section aria-labelledby="alte_schule_cookies"><h3 id="alte_schule_cookies"><a href="#alte_schule_cookies">Alte Schule: Cookies</a></h3><div class="section-content"><p>Das Konzept der client-seitigen Speicherung gibt es schon lange. Seit den frühen Tagen des Webs haben Websites <a href="/de/docs/Web/HTTP/Cookies">Cookies</a> verwendet, um Informationen zu speichern, um die Benutzererfahrung auf Websites zu personalisieren. Sie sind die früheste Form von client-seitiger Speicherung, die im Web häufig genutzt wird.</p> <p>Heutzutage gibt es einfachere Mechanismen, um client-seitige Daten zu speichern, 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 immer noch häufig verwendet, um Daten zu speichern, die mit der Personalisierung und dem Zustand des Benutzers zusammenhängen, z. B. Sitzungs-IDs und Zugriffstoken. 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="neue_schule_web_storage_und_indexeddb"><h3 id="neue_schule_web_storage_und_indexeddb"><a href="#neue_schule_web_storage_und_indexeddb">Neue Schule: 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 Datenobjekte, 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 Benutzers, ob er eingeloggt ist, welche Hintergrundfarbe verwendet werden soll usw.</li> <li>Die <a href="/de/docs/Web/API/IndexedDB_API">IndexedDB API</a> bietet dem Browser ein vollständiges Datenbanksystem zum Speichern komplexer Daten. Dies kann für alles verwendet werden, von vollständigen Sätzen von Kundenunterlagen bis hin zu komplexen Datentypen wie Audio- oder Videodateien.</li> </ul> <p>Sie erfahren weiter unten mehr über diese APIs.</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 zum Speichern von HTTP-Antworten auf bestimmte Anfragen konzipiert und sehr nützlich für Dinge wie das Speichern von Website-Ressourcen offline, sodass die Website anschließend ohne Netzwerkverbindung genutzt werden kann. Cache wird normalerweise in Kombination mit der <a href="/de/docs/Web/API/Service_Worker_API">Service Worker API</a> verwendet, obwohl es nicht zwingend erforderlich ist.</p> <p>Die Nutzung 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-speicherung_von_ressourcen">Offline-Speicherung von Ressourcen</a> unten zeigen werden.</p></div></section><section aria-labelledby="speicherung_einfacher_daten_—_web_storage"><h2 id="speicherung_einfacher_daten_—_web_storage"><a href="#speicherung_einfacher_daten_—_web_storage">Speicherung 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 Zeichenfolgen, 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>Gehen Sie zuerst zu unserer <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html" class="external" target="_blank">Web Storage Blankovorlage</a> auf GitHub (öffnen Sie dies in einem neuen Tab).</p> </li> <li> <p>Öffnen Sie die JavaScript-Konsole der Entwickler-Tools Ihres Browsers.</p> </li> <li> <p>Alle Ihre Web Storage-Daten befinden sich in zwei objektartigen Strukturen innerhalb des Browsers: <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>. Der erste speichert Daten, solange der Browser geöffnet ist (die Daten gehen verloren, wenn der Browser geschlossen wird) und der zweite speichert Daten, auch nachdem der Browser geschlossen und dann erneut geöffnet wurde. Wir werden den zweiten in diesem Artikel verwenden, da er im Allgemeinen nützlicher ist.</p> <p>Die <a href="/de/docs/Web/API/Storage/setItem"><code>Storage.setItem()</code></a>-Methode ermöglicht es Ihnen, einen Dateneintrag im Speicher zu speichern — sie erfordert zwei Parameter: den Namen des Eintrags und dessen 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 <a href="/de/docs/Web/API/Storage/getItem"><code>Storage.getItem()</code></a>-Methode erfordert einen Parameter — den Namen eines Dateneintrags, den Sie abrufen möchten — und gibt den Wert dieses Eintrags 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> jetzt den Wert des <code>name</code>-Dateneintrags enthält.</p> </li> <li> <p>Die <a href="/de/docs/Web/API/Storage/removeItem"><code>Storage.removeItem()</code></a>-Methode erfordert einen Parameter — den Namen eines Dateneintrags, den Sie entfernen möchten — und entfernt diesen Eintrag aus der Webspeicherung. 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 jetzt <code>null</code> zurückgeben — der <code>name</code>-Eintrag existiert nicht mehr in der Webspeicherung.</p> </li> </ol></div></section><section aria-labelledby="die_daten_bleiben_erhalten!"><h3 id="die_daten_bleiben_erhalten!"><a href="#die_daten_bleiben_erhalten!">Die Daten bleiben erhalten!</a></h3><div class="section-content"><p>Ein wichtiges Merkmal der Webspeicherung ist, dass die Daten zwischen Seitenaufrufen (und sogar beim Herunterfahren des Browsers, im Fall von <code>localStorage</code>) bestehen bleiben. Schauen wir uns das in Aktion an.</p> <ol> <li> <p>Öffnen Sie unsere Web Storage Blankovorlage erneut, diesmal aber in einem anderen Browser als dem, in dem Sie dieses Tutorial geöffnet haben! Dies erleichtert den Umgang damit.</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 den zurückgegebenen Name-Eintrag sehen.</p> </li> <li> <p>Schließen Sie nun den Browser und öffnen Sie ihn erneut.</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 weiterhin verfügbar ist, auch nachdem der Browser geschlossen und dann erneut geöffnet wurde.</p> </li> </ol></div></section><section aria-labelledby="getrennter_speicher_für_jede_domain"><h3 id="getrennter_speicher_für_jede_domain"><a href="#getrennter_speicher_für_jede_domain">Getrennter Speicher für jede Domain</a></h3><div class="section-content"><p>Es gibt einen separaten Datenspeicher für jede Domain (jede separate Webadresse, die im Browser geladen wird). Sie werden sehen, dass, wenn Sie zwei Websites laden (zum Beispiel google.com und amazon.com) und versuchen, einen Eintrag auf einer Website zu speichern, dieser auf der anderen Website nicht verfügbar ist.</p> <p>Dies ist sinnvoll – 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_komplexeres_beispiel"><h3 id="ein_komplexeres_beispiel"><a href="#ein_komplexeres_beispiel">Ein komplexeres Beispiel</a></h3><div class="section-content"><p>Lassen Sie uns dieses neu erworbene Wissen anwenden, indem wir ein funktionierendes Beispiel schreiben, um Ihnen eine Vorstellung davon zu geben, wie Webspeicherung verwendet werden kann. Unser Beispiel ermöglicht es Ihnen, einen Namen einzugeben, woraufhin die Seite so aktualisiert wird, dass Sie eine personalisierte Begrüßung erhalten. Dieser Zustand bleibt auch über Seiten-/Browser-Reloads hinweg bestehen, da der Name in der Webspeicherung gespeichert ist.</p> <p>Sie können 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> finden – dies enthält eine Website mit einem Header, Inhalt und Fußzeile sowie ein Formular zum Eingeben Ihres Namens.</p> <p> <img src="/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage/web-storage-demo.png" alt="Ein Screenshot einer Website mit Header-, Inhalts- und Fußzeile. Der Header hat links einen Begrüßungstext und rechts eine Schaltfläche mit der Bezeichnung 'Vergessen'. Der Inhalt hat eine Überschrift gefolgt von zwei Absätzen Blindtext. Die Fußzeile lautet '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 zunächst 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>. Wir müssen diese erstellen und unseren JavaScript-Code hineinschreiben. Erstellen Sie eine <code>index.js</code>-Datei im selben Verzeichnis wie Ihre HTML-Datei.</p> </li> <li> <p>Wir beginnen damit, Verweise auf alle HTML-Funktionen zu erstellen, die wir in diesem Beispiel manipulieren müssen – wir werden sie alle als Konstanten erstellen, da diese Verweise im Lebenszyklus der App nicht geändert werden 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 einbinden, um zu verhindern, dass das Formular sich tatsächlich selbst abschickt, wenn die Absenden-Schaltfläche gedrückt wird, da dies nicht das gewünschte Verhalten ist. Fügen Sie das folgende 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>Jetzt müssen wir einen Ereignis-Listener hinzufügen, dessen Handlerfunktion ausgeführt wird, wenn die Schaltfläche „Sag Hallo“ geklickt wird. Die Kommentare erläutern im Detail, was jeder Teil tut, aber im Wesentlichen nehmen wir hier den Namen, den der Benutzer in das Texteingabefeld eingegeben hat, speichern ihn in der Webspeicherung mit <code>setItem()</code> und führen dann eine Funktion namens <code>nameDisplayCheck()</code> aus, die das Aktualisieren des tatsächlichen Website-Textes übernimmt. Fügen Sie dies 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>// 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 dieser Stelle benötigen wir auch einen Ereignis-Handler, der eine Funktion ausführt, wenn die Schaltfläche „Vergessen“ geklickt wird – diese wird nur angezeigt, nachdem die Schaltfläche „Sag Hallo“ geklickt wurde (die beiden Formularzustände wechseln hin und her). In dieser Funktion entfernen wir den <code>name</code>-Eintrag aus der Webspeicherung mit <code>removeItem()</code> und führen dann erneut <code>nameDisplayCheck()</code> aus, um das Display 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>Es ist nun an der Zeit, die <code>nameDisplayCheck()</code>-Funktion selbst zu definieren. Hier überprüfen wir, ob der Namenseintrag in der Webspeicherung gespeichert wurde, indem wir <code>localStorage.getItem('name')</code> als bedingten Test verwenden. Wenn der Name gespeichert wurde, wird dieser Aufruf als <code>true</code> ausgewertet; wenn nicht, wird der Aufruf als <code>false</code> ausgewertet. Wenn der Aufruf als <code>true</code> ausgewertet wird, zeigen wir eine personalisierte Begrüßung an, zeigen den „Vergessen“-Teil des Formulars an und verbergen den „Sag Hallo“-Teil des Formulars. Wenn der Aufruf als <code>false</code> ausgewertet wird, zeigen wir eine generische Begrüßung an und verhalten uns umgekehrt. Fügen Sie den folgenden Code 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>// 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 <code>nameDisplayCheck()</code>-Funktion ausführen, wenn die Seite geladen wird. Wenn wir dies nicht tun, dann würde die personalisierte Begrüßung nicht über Seitenreloads 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 bleibt, ist Ihr 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">abgeschlossene Version hier live sehen</a>.</p> <div class="notecard note"> <p><strong>Hinweis:</strong> Es gibt ein weiteres, etwas komplexeres Beispiel, das Sie in <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 abgeschlossenen 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 vollständig geladen ist.</p> </div></div></section><section aria-labelledby="speicherung_komplexer_daten_—_indexeddb"><h2 id="speicherung_komplexer_daten_—_indexeddb"><a href="#speicherung_komplexer_daten_—_indexeddb">Speicherung komplexer Daten — IndexedDB</a></h2><div class="section-content"><p>Die <a href="/de/docs/Web/API/IndexedDB_API">IndexedDB API</a> (manchmal als IDB abgekürzt) ist ein komplettes Datenbanksystem, das im Browser verfügbar ist, in dem Sie komplexe zusammenhängende Daten speichern können, deren Typen nicht auf einfache Werte wie Zeichenfolgen 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 erlaubt es Ihnen, eine Datenbank zu erstellen und dann „object stores“ in dieser Datenbank zu erstellen. „Object stores“ sind wie Tabellen in einer relationalen Datenbank, und jeder „object store“ 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 ist dies mit Kosten verbunden: IndexedDB ist viel komplexer zu verwenden als die Web Storage API. In diesem Abschnitt werden wir nur an der Oberfläche dessen kratzen, wozu es fähig ist, aber wir werden Ihnen genug geben, um anzufangen.</p></div></section><section aria-labelledby="durcharbeiten_eines_notizen-speicherbeispiels"><h3 id="durcharbeiten_eines_notizen-speicherbeispiels"><a href="#durcharbeiten_eines_notizen-speicherbeispiels">Durcharbeiten eines Notizen-Speicherbeispiels</a></h3><div class="section-content"><p>Hier führen wir Sie Schritt für Schritt durch ein Beispiel, das es Ihnen ermöglicht, Notizen in Ihrem Browser zu speichern und sie wann immer Sie möchten anzuzeigen und zu löschen, und erklären die grundlegendsten Teile von IDB, während wir es zusammen aufbauen.</p> <p>Die App sieht in etwa so aus:</p> <p> <img src="/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage/idb-demo.png" alt="Ein IndexDB Notizen-Demo-Screenshot mit 4 Abschnitten. Der erste Abschnitt ist der Header. Der zweite Abschnitt listet alle Notizen auf, die erstellt wurden. Es hat zwei Notizen, jede mit einem Löschen-Button. Ein dritter Abschnitt ist ein Formular mit 2 Eingabefeldern für 'Notiztitel' und 'Notiztext' und einem Knopf mit der Aufschrift '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, die individuell bearbeitet werden können. Der JavaScript-Code, den wir im Folgenden durchgehen werden, enthält detaillierte Kommentare, um Ihnen beim Verständnis zu helfen.</p></div></section><section aria-labelledby="erste_schritte"><h3 id="erste_schritte"><a href="#erste_schritte">Erste Schritte</a></h3><div class="section-content"><ol> <li>Erstellen Sie zuerst 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 Ihrem lokalen Rechner.</li> <li>Schauen Sie sich die Dateien an. Sie werden sehen, dass das HTML eine Website mit einem Header und einer Fußzeile sowie einem Hauptinhaltbereich definiert, der einen Platz zum Anzeigen von Notizen und ein Formular zum Eingeben neuer Notizen in die Datenbank enthält. Das CSS bietet einige Stile, um zu verdeutlichen, 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, sowie auf das Titel- und Körper-<a href="/de/docs/Web/HTML/Element/input"><code><input></code></a> Elemente, das <a href="/de/docs/Web/HTML/Element/form"><code><form></code></a> selbst und den <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 nun bereit, Code darin hinzuzufügen.</li> </ol></div></section><section aria-labelledby="initiale_datenbankeinrichtung"><h3 id="initiale_datenbankeinrichtung"><a href="#initiale_datenbankeinrichtung">Initiale Datenbankeinrichtung</a></h3><div class="section-content"><p>Schauen wir uns jetzt an, was wir tun müssen, um eigentlich 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 darzustellen, das unsere Datenbank repräsentiert. Wir werden dies an einigen Stellen verwenden, daher haben wir es global hier deklariert, um die Dinge zu vereinfachen.</p> </li> <li> <p>Als Nächstes fügen Sie Folgendes 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, um Version <code>1</code> einer Datenbank namens <code>notes_db</code> zu öffnen. Wenn diese nicht bereits existiert, wird sie von anschließendem Code für Sie erstellt. Sie werden dieses Anforderungsmuster sehr oft in der IndexedDB sehen. Datenbankoperationen benötigen Zeit. Sie möchten den Browser nicht einfrieren, während Sie auf die Ergebnisse warten, daher sind Datenbankoperationen <a href="/de/docs/Glossary/Asynchronous">asynchron</a>, d.h. sie geschehen nicht sofort, sondern irgendwann in der Zukunft, und Sie werden benachrichtigt, wenn sie fertig sind.</p> <p>Um dies in IndexedDB zu handhaben, erstellen Sie ein Anforderungsobjekt (das Sie nach Belieben benennen können – wir haben es hier <code>openRequest</code> genannt, damit es obvious ist, wofür es ist). Sie verwenden dann Ereignis-Handler, um Code auszuführen, wenn die Anfrage abschließt, fehlschlägt usw., was Sie weiter unten in Aktion sehen werden.</p> <div class="notecard note"> <p><strong>Hinweis:</strong> Die Versionsnummer ist wichtig. Wenn Sie Ihre Datenbank aktualisieren möchten (zum Beispiel durch Ändern der Tabellenstruktur), müssen Sie Ihren Code erneut ausführen, jedoch mit einer erhöhten Versionsnummer und einem im <code>upgradeneeded</code>-Handler (siehe unten) spezifizierten abweichenden Schema usw. Wir werden das Upgrade von Datenbanken in diesem Tutorial nicht behandeln.</p> </div> </li> <li> <p>Fügen Sie nun die folgenden Ereignis-Handler direkt unter Ihrem vorherigen Hinzufügung ein:</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. Dies ermöglicht es Ihnen, auf dieses Problem zu 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 Anfrage erfolgreich zurückkehrt, 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 gemacht, 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 es jetzt aus, damit die Notizen, die sich bereits in der Datenbank befinden, angezeigt werden, sobald die Seite geladen wird. Sie werden <code>displayData()</code> später definiert sehen.</p> </li> <li> <p>Schließlich für diesen Abschnitt fügen wir wahrscheinlich den wichtigsten Ereignis-Handler für die 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 größeren Versionsnummer als die bestehende gespeicherte Datenbank geöffnet wird (bei Durchführung eines Upgrades). 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 (Struktur) unserer Datenbank; das heißt die Menge an Spalten (oder Feldern), die sie enthält. Hier greifen wir zuerst auf eine Referenz zur bestehenden Datenbank aus der <code>result</code>-Eigenschaft des Ziels des Ereignisses (<code>e.target.result</code>) zu, welches das Anforderungsobjekt ist. Dies entspricht der Zeile <code>db = openRequest.result;</code> innerhalb des <code>success</code>-Ereignis-Handlers, aber wir müssen dies hier separat tun, da der <code>upgradeneeded</code>-Ereignis-Handler (falls benötigt) 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>Dann verwenden wir <a href="/de/docs/Web/API/IDBDatabase/createObjectStore"><code>IDBDatabase.createObjectStore()</code></a>, um ein neues Objekt-Lager in unserer geöffneten Datenbank zu erstellen, das <code>notes_os</code> genannt wird. Dies entspricht einer einzelnen Tabelle in einem konventionellen Datenbanksystem. Wir haben ihm den Namen Notizen gegeben und auch ein <code>autoIncrement</code>-Schlüsselfeld namens <code>id</code> spezifiziert – in jedem neuen Datensatz wird diesem automatisch ein inkrementierter Wert gegeben – der Entwickler muss dies nicht explizit setzen. Als Schlüssel wird das <code>id</code>-Feld verwendet, um Datensätze eindeutig zu identifizieren, etwa beim Löschen oder Anzeigen eines Datensatzes.</p> <p>Wir erstellen auch zwei andere Indizes (Felder) mit der Methode <a href="/de/docs/Web/API/IDBObjectStore/createIndex"><code>IDBObjectStore.createIndex()</code></a>: <code>title</code> (welcher einen Titel für jede Notiz enthält) und <code>body</code> (welcher den Textinhalt der Notiz enthält).</p> </li> </ol> <p>So mit diesem Datenbankschema, wenn wir anfangen, Datensätze in die Datenbank einzufügen, wird jeder als ein Objekt in folgender Struktur 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 in die Datenbank hinzufügen können. Dies geschieht mit dem Formular auf unserer Seite.</p> <p>Unter Ihrem vorherigen Ereignis-Handler fügen Sie die folgende Zeile hinzu, die einen <code>submit</code>-Ereignis-Handler einrichtet, der eine Funktion namens <code>addData()</code> ausführt, wenn das Formular übermittelt 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>Lassen Sie uns nun die <code>addData()</code>-Funktion definieren. Fügen Sie dies 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; unterteilt gesagt, wir:</p> <ul> <li>Führen <a href="/de/docs/Web/API/Event/preventDefault"><code>Event.preventDefault()</code></a> am Ereignisobjekt aus, um zu verhindern, dass das Formular tatsächlich auf die konventionelle Art übermittelt wird (dies würde ein Seitenrefresh verursachen und das Erlebnis verderben).</li> <li>Erstellen ein Objekt, das einen Datensatz darstellt, der in die Datenbank eingegeben werden soll, und füllen es mit Werten aus den Formulareingaben. Beachten Sie, dass wir keinen <code>id</code>-Wert explizit einfügen müssen – wie bereits erläutert, wird dieser automatisch gefüllt.</li> <li>Öffnen eine <code>readwrite</code>-Transaktion gegen das <code>notes_os</code> Objekt-Store mit der <a href="/de/docs/Web/API/IDBDatabase/transaction"><code>IDBDatabase.transaction()</code></a>-Methode. Dieses Transaktionsobjekt erlaubt uns den Zugriff auf das Objekt-Store, sodass wir etwas damit tun können, z. B. einen neuen Datensatz hinzufügen.</li> <li>Greifen auf das Objekt-Lager mit der <a href="/de/docs/Web/API/IDBTransaction/objectStore"><code>IDBTransaction.objectStore()</code></a>-Methode zu und speichern das Ergebnis in der Variablen <code>objectStore</code>.</li> <li>Fügen den neuen Datensatz mit <a href="/de/docs/Web/API/IDBObjectStore/add"><code>IDBObjectStore.add()</code></a> in die Datenbank ein. Dies erstellt ein Anforderungsobjekt, in der gleichen Art und Weise, wie wir es vorher gesehen haben.</li> <li>Fügen eine Reihe von Ereignis-Handler am <code>request</code>- und <code>transaction</code>-Objekt hinzu, um Code an kritischen Punkten im Lebenszyklus auszuführen. Sobald die Anfrage erfolgreich abgeschlossen ist, leeren wir die Formulareingaben, um die Eingabe der nächsten Notiz vorzubereiten. 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 besser 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>Erneut, brechen wir dies herunter:</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 Sie am Ende eine riesige Liste von duplizierten Inhalten erhalten, die bei jeder Aktualisierung hinzugefügt wird.</li> <li>Als nächstes bekommen wir eine Referenz zum <code>notes_os</code>-Objekt-Store mittels <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> wie wir es in <code>addData()</code> gemacht haben, außer dass wir sie hier in einer Zeile verketten.</li> <li>Der nächste Schritt ist die Verwendung der <a href="/de/docs/Web/API/IDBObjectStore/openCursor"><code>IDBObjectStore.openCursor()</code></a>-Methode, um eine Anfrage für einen Cursor zu öffnen – das ist ein Konstrukt, das verwendet werden kann, um die Datensätze in einem Object-Store zu durchlaufen. Wir verketten einen <code>success</code>-Ereignis-Handler an das Ende dieser Zeile, um den Code prägnanter zu machen – wenn der Cursor erfolgreich zurückgegeben wird, wird der Handler ausgeführt.</li> <li>Wir bekommen 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 überprüfen wir, ob der Cursor einen Datensatz aus dem Datenspeicher enthält (<code>if (cursor){ }</code>) – falls ja, erstellen wir ein 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 geklickt, diese Notiz mit 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 bewegen und den Inhalt des <code>if</code>-Blocks erneut auszuführen. Wenn es einen weiteren Datensatz gibt, zu dem iteriert wird, wird dies bewirken, dass er in die Seite eingefügt wird, und dann wird <code>continue()</code> erneut ausgeführt, und so weiter.</li> <li>Wenn es keine weiteren Datensätze mehr gibt, zu denen iteriert werden kann, wird <code>cursor</code> <code>undefined</code> zurückgeben, und somit wird der <code>else</code>-Block anstelle des <code>if</code>-Blocks ausgeführt. Dieser Block überprüft, ob keine Notizen in das <code><ul></code> eingefügt wurden – falls nicht, wird eine Nachricht eingefügt, die sagt, dass keine Notiz gespeichert wurde.</li> </ul></div></section><section aria-labelledby="löschen_einer_notiz"><h3 id="löschen_einer_notiz"><a href="#löschen_einer_notiz">Löschen einer Notiz</a></h3><div class="section-content"><p>Wie oben erwähnt, wird eine Notiz gelöscht, wenn der Löschen-Button der Notiz gedrückt wird. Dies wird durch die <code>deleteItem()</code>-Funktion erreicht, die wie folgt aussieht:</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 hiervon könnte eine Erklärung benötigen – wir rufen die ID des zu löschenden Datensatzes über <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> ab – erinnern Sie sich, dass die ID des Datensatzes bei der ersten Anzeige in einem <code>data-note-id</code>-Attribut bei den <code><li></code> gespeichert wurde. Wir müssen das Attribut jedoch über das globale eingebaute <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Number"><code>Number()</code></a>-Objekt verarbeiten, da es vom Datentyp <code>string</code> ist und daher von der Datenbank, die eine Zahl erwartet, nicht erkannt werden würde.</li> <li>Anschließend erhalten wir über das uns bereits bekannte Muster eine Referenz zum Objekt-Store 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, indem wir ihm die ID übergeben.</li> <li>Wenn die Datenbank-Transaktion abgeschlossen ist, löschen wir die Notiz-<code><li></code> aus dem DOM und führen erneut die Überprüfung durch, um zu sehen, ob das <code><ul></code> jetzt leer ist, und fügen bei Bedarf eine Notiz ein.</li> </ul> <p>Das ist alles! Ihr Beispiel sollte nun funktionieren.</p> <p>Wenn Sie Schwierigkeiten damit haben, <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/" class="external" target="_blank">können Sie es gerne mit unserem Live-Beispiel 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="speicherung_komplexer_daten_über_indexeddb"><h3 id="speicherung_komplexer_daten_über_indexeddb"><a href="#speicherung_komplexer_daten_über_indexeddb">Speicherung komplexer Daten über IndexedDB</a></h3><div class="section-content"><p>Wie bereits 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 Bild-Blobs. Und es ist nicht viel schwieriger als andere Datentypen.</p> <p>Um zu zeigen, wie es 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 Videoladen</a> geschrieben (siehe es auch <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/" class="external" target="_blank">hier live laufen</a>). Beim ersten Ausführen des Beispiels lädt es alle Videos vom Netzwerk herunter, speichert sie in einer IndexedDB-Datenbank und zeigt die Videos dann in der UI innerhalb von <a href="/de/docs/Web/HTML/Element/video"><code><video></code></a>-Elementen an. Beim zweiten Ausführen findet es die Videos in der Datenbank und ruft sie von dort ab, bevor es sie anzeigt – das macht die nachfolgenden Ladezeiten viel schneller und weniger bandbreitenlastig.</p> <p>Schauen wir uns die interessantesten Teile des Beispiels an. Wir werden nicht alles durchgehen – vieles davon ist dem vorherigen Beispiel ähnlich, 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>Zu Beginn, 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 Datenbank <code>videos</code> zu laden.</p> <p>Wenn jedes Video in der Datenbank gefunden wird (überprüft durch Prüfen, ob <code>request.result</code> als <code>true</code> auswertet – wenn der Datensatz nicht vorhanden ist, wird er <code>undefined</code> sein), werden die Videosdateien (als Blobs gespeichert) und der Videoname direkt an die <code>displayVideo()</code>-Funktion weitergegeben, um sie in der UI zu platzieren. Andernfalls wird der Videoname an die Funktion <code>fetchVideoFromNetwork()</code> übergeben, um, Sie haben es erraten, das Video aus dem Netzwerk abzurufen.</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>Der folgende Schnipsel stammt aus der Funktion <code>fetchVideoFromNetwork()</code> – hier holen wir MPEG-4- und WebM-Versionen des Videos über zwei separate <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 und uns eine Objekt-Darstellung der Videos zu geben, die später gespeichert und angezeigt werden kann.</p> <p>Hier haben wir jedoch ein Problem – diese beiden Anfragen sind asynchron, aber wir möchten die Videos nur dann anzeigen oder speichern, wenn beide Zusagen erfüllt sind. Glücklicherweise gibt es eine eingebaute Methode, die ein solches Problem behandelt – <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/all"><code>Promise.all()</code></a>. Diese nimmt ein Argument – Referenzen zu all den einzelnen Zusagen, die Sie auf Erfüllung prüfen möchten, in einem Array abgelegt – und gibt eine Zusage zurück, die erfüllt wird, wenn alle Einzelzusagen erfüllt sind.</p> <p>Im <code>then()</code>-Handler für diese Zusage rufen wir die Funktion <code>displayVideo()</code> auf, wie wir es zuvor getan haben, um die Videos in der UI anzuzeigen, und rufen dann 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 zum Hinzufügen von Daten zur Datenbank gesehen haben, sehr ähnlich – wir öffnen eine <code>readwrite</code>-Transaktion und erhalten eine Referenz zu unserem <code>videos_os</code>-Objekt-Store, erstellen ein Objekt, das den Datensatz darstellt, der zur Datenbank hinzugefügt werden soll, 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 UI einzufügen, und sie dann zur Seite hinzufügt. Die interessantesten Teile davon sind die unten gezeigten – um unsere Videoblobs tatsächlich in einem <code><video></code>-Element anzuzeigen, müssen wir Objekt-URLs erstellen (interne URLs, die auf die in Erinnerung gespeicherten Videoblobs verweisen) mit der Methode <a href="/de/docs/Web/API/URL/createObjectURL_static"><code>URL.createObjectURL()</code></a>. Sobald dies geschehen ist, können wir die Objekt-URLs als Werte unserer <code>src</code>-Attribute des <a href="/de/docs/Web/HTML/Element/source"><code><source></code></a>-Elements 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-speicherung_von_ressourcen"><h2 id="offline-speicherung_von_ressourcen"><a href="#offline-speicherung_von_ressourcen">Offline-Speicherung von Ressourcen</a></h2><div class="section-content"><p>Das obige Beispiel zeigt bereits, wie man eine App erstellt, die große Ressourcen in einer IndexedDB-Datenbank speichert und so das Herunterladen mehr als einmal vermeidet. Dies ist bereits eine große Verbesserung der Benutzererfahrung, aber es fehlt noch eine Sache – die Haupt-HTML-, CSS- und JavaScript-Dateien müssen immer noch jedes Mal heruntergeladen werden, wenn die Seite aufgerufen wird, was bedeutet, dass sie nicht funktioniert, wenn keine Netzwerkverbindung besteht.</p> <p> <img src="/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage/ff-offline.png" alt="Firefox-Offline-Bildschirm mit einer Abbildung einer Cartoon-Figur auf der linken Seite, die mit der rechten Hand einen zwei-poligen Stecker und mit der linken Hand eine zwei-polige Steckdose hält. Auf der rechten Seite gibt es eine Offline-Modus-Nachricht und einen Button mit der Aufschrift 'Erneut versuchen'." width="765" height="307" loading="lazy"> </p> <p>Hier kommen <a href="/de/docs/Web/API/Service_Worker_API">Service Worker</a> und die verwandte <a href="/de/docs/Web/API/Cache">Cache API</a> ins Spiel.</p> <p>Ein Service Worker ist eine JavaScript-Datei, die beim Zugriff durch einen Browser gegen eine bestimmte Herkunft (Website oder einen Teil einer Website auf einer bestimmten Domain) registriert wird. Wenn er registriert ist, kann er Seiten an dieser Herkunft kontrollieren. Er tut dies, indem er zwischen einer geladenen Seite und dem Netzwerk sitzt und Netzwerkanfragen abfängt, die an diese Herkunft gerichtet sind.</p> <p>Wenn er eine Anfrage abfängt, kann er alles damit machen, was Sie wollen (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 dann das Bereitstellen dieser als Antwort auf eine Anfrage anstelle der Antworten aus dem Netzwerk. Tatsächlich erlaubt es, eine Website komplett offline arbeiten zu lassen.</p> <p>Die Cache-API ist ein weiteres client-seitiges Speichermechanismus, mit einem kleinen Unterschied – sie ist darauf 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 dies aussehen könnte. Wir haben eine weitere Version des Video Store-Beispiels erstellt, das wir im vorherigen Abschnitt gesehen haben – dies funktioniert identisch, außer dass es auch die HTML-, CSS- und JavaScript-Dateien in der Cache-API über einen Service Worker speichert und das Beispiel offline laufen lässt!</p> <p>Siehe <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/" class="external" target="_blank">IndexedDB Videoladen mit Service Worker live laufen</a>, und sehen Sie auch den <a href="https://github.com/mdn/learning-area/tree/main/javascript/apis/client-side-storage/cache-sw/video-store-offline" class="external" target="_blank">Quellcode</a>.</p> <h4 id="registrierung_des_service_workers">Registrierung des Service Workers</h4> <p>Das erste, was zu beachten ist, ist, dass es ein zusätzliches Stück Code 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>). Wir führen zuerst einen Feature-Erkennungstest durch, um zu sehen, ob das <code>serviceWorker</code>-Mitglied im <a href="/de/docs/Web/API/Navigator"><code>Navigator</code></a> vorhanden ist. Wenn das <code>true</code> zurückgibt, dann wissen wir, dass zumindest die Grundlagen der Service Worker unterstützt werden. Innerhalb hier verwenden wir die Methode <a href="/de/docs/Web/API/ServiceWorkerContainer/register"><code>ServiceWorkerContainer.register()</code></a>, um einen Service Worker, der in der Datei <code>sw.js</code> enthalten ist, gegen die Herkunft, an der er sich befindet, zu registrieren, sodass er Seiten im selben Verzeichnis wie er oder Unterverzeichnissen kontrollieren kann. Wenn Ihr 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 zur Ursprungsseite, nicht zur JavaScript-Datei, die den Code enthält. Der Service Worker befindet sich unter <code>https://mdn.github.io/learning-area/javascript/apis/player-cache-sw/video-store-offline/sw.js</code>. Die Ursprungsseite ist <code>https://mdn.github.io</code>, und daher muss der angegebene Pfad <code>/learning-area/javascript/apis/player-cache-sw/video-store-offline/sw.js</code> sein. Wenn Sie dieses Beispiel auf Ihrem eigenen Server hosten möchten, müssen Sie dies entsprechend ändern. Dies ist etwas verwirrend, aber es muss aus Sicherheitsgründen so funktionieren.</p> </div> <h4 id="installation_des_service_workers">Installation des Service Workers</h4> <p>Beim nächsten Mal, wenn eine Seite unter der Kontrolle des Service Workers aufgerufen wird (z.B. beim Hinweis des Beispiels), wird der Service Worker gegen diese Seite installiert, was bedeutet, dass er beginnt, sie zu kontrollieren. Wenn dies geschieht, wird ein <code>install</code>-Ereignis gegen den Service Worker ausgelöst; Sie können Code innerhalb des Service Workers selbst schreiben, der auf die Installation reagiert.</p> <p>Schauen wir uns ein Beispiel an, in der Datei <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> (der Service Worker). Sie werden sehen, dass die Listener für die Installation an <code>self</code> registriert sind. Dieses <code>self</code>-Schlüsselwort ist eine Möglichkeit, aus der Datei des Service Workers selbst auf den globalen Bereich des Service Workers 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 am Ereignisobjekt verfügbar ist, um zu signalisieren, dass der Browser die Installation des Service Workers nicht abschließen sollte, bis das darin enthaltene Versprechen 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 einem IndexedDB-Objekt-Store). 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 darstellt. Dann verwenden wir die Methode <a href="/de/docs/Web/API/Cache/addAll"><code>Cache.addAll()</code></a>, um eine Reihe von Ressourcen abzurufen und deren Antworten im Cache zu speichern.</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 erledigt.</p> <h4 id="reaktion_auf_weitere_anfragen">Reaktion auf weitere Anfragen</h4> <p>Mit dem Service Worker registriert und gegen unsere HTML-Seite installiert sowie den relevanten Ressourcen, die alle in unserem Cache hinzugefügt wurden, sind wir fast startklar. Es gibt noch eine Sache zu tun: Code schreiben, um auf weitere Netzwerkanfragen zu reagieren.</p> <p>Das ist es, was das zweite Stück Code in <code>sw.js</code> tut. Wir fügen einen weiteren Listener zum Service Worker globalen Bereich hinzu, der den Handler aufruft, wenn das <code>fetch</code>-Ereignis ausgelöst wird. Dies geschieht immer dann, wenn der Browser eine Anfrage für eine Ressource in dem Verzeichnis stellt, gegen das der Service Worker registriert ist.</p> <p>Innerhalb des Handlers protokollieren wir zunächst die URL der angeforderten Ressource. Wir liefern dann eine benutzerdefinierte Antwort auf die Anfrage, indem wir die Methode <a href="/de/docs/Web/API/FetchEvent/respondWith"><code>FetchEvent.respondWith()</code></a> verwenden.</p> <p>Innerhalb dieses Blocks verwenden wir <a href="/de/docs/Web/API/CacheStorage/match"><code>CacheStorage.match()</code></a>, um zu überprüfen, ob eine passende Anfrage (d. h. entspricht der URL) in einem beliebigen Cache gefunden werden kann. Dieses Versprechen erfüllt sich mit der passenden Antwort, wenn ein Match gefunden wird, oder <code>undefined</code>, wenn nicht.</p> <p>Wenn ein Match gefunden wird, geben wir es als benutzerdefinierte Antwort zurück. Wenn nicht, holen wir die Antwort 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 es für unseren Service Worker. Es gibt eine ganze Menge mehr, was Sie damit tun können – für weit mehr Details schauen Sie sich das <a href="https://github.com/mdn/serviceworker-cookbook" class="external" target="_blank">Service Worker Kochbuch</a> an. 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 der Fall ist, können Sie:</p> <ul> <li>Versuchen Sie, Ihr Netzwerk zu trennen / Ihr WLAN auszuschalten.</li> <li>Wählen Sie <em>Datei > Offline arbeiten</em> aus, wenn Sie Firefox verwenden.</li> <li>Gehen Sie zu den Entwickler-Tools, wählen Sie dann <em>Anwendung > Service Worker</em>, und aktivieren Sie das Kontrollkästchen <em>Offline</em>, wenn Sie Chrome verwenden.</li> </ul> <p>Wenn Sie Ihre Beispiel-Seite erneut aktualisieren, sollten Sie sehen, dass sie einwandfrei geladen wird. Alles wird offline gespeichert – die Seitenressourcen 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 jetzt. Wir hoffen, Sie fanden unseren Überblick über client-seitige Speichertechnologien nützlich.</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/JavaScript/Client-side_web_APIs/Video_and_audio_APIs"><span class="button-wrap"> Zurück </span></a></li> <li><a class="button secondary" href="/de/docs/Learn/JavaScript/Client-side_web_APIs"><span class="button-wrap"> Übersicht: Client-Side-Web-APIs</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/javascript/client-side_web_apis/client-side_storage/index.md?plain=1" title="Folder: de/learn/javascript/client-side_web_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%2FJavaScript%2FClient-side_web_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%2Fjavascript%2Fclient-side_web_apis%2Fclient-side_storage%60%0A*+MDN+URL%3A+https%3A%2F%2Fdeveloper.mozilla.org%2Fde%2Fdocs%2FLearn%2FJavaScript%2FClient-side_web_APIs%2FClient-side_storage%0A*+GitHub+URL%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Ftranslated-content-de%2Fblob%2Fmain%2Ffiles%2Fde%2Flearn%2Fjavascript%2Fclient-side_web_apis%2Fclient-side_storage%2Findex.md%0A*+Last+commit%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Ftranslated-content-de%2Fcommit%2Fnull%0A*+Document+last+modified%3A+*date+not+known*%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://mozilla.social/@mdn" target="_blank" rel="me noopener noreferrer"><span class="icon icon-mastodon"></span><span class="visually-hidden">MDN on Mastodon</span></a></li><li><a href="https://twitter.com/mozdevnet" target="_blank" rel="noopener noreferrer"><span class="icon icon-twitter-x"></span><span class="visually-hidden">MDN on X (formerly Twitter)</span></a></li><li><a href="https://github.com/mdn/" target="_blank" rel="noopener noreferrer"><span class="icon icon-github-mark-small"></span><span class="visually-hidden">MDN on GitHub</span></a></li><li><a href="/en-US/blog/rss.xml" target="_blank"><span class="icon icon-feed"></span><span class="visually-hidden">MDN Blog RSS Feed</span></a></li></ul></div><div class="page-footer-nav-col-1"><h2 class="footer-nav-heading">MDN</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a href="/en-US/about">About</a></li><li class="footer-nav-item"><a href="/en-US/blog/">Blog</a></li><li class="footer-nav-item"><a href="https://www.mozilla.org/en-US/careers/listings/?team=ProdOps" target="_blank" rel="noopener noreferrer">Careers</a></li><li class="footer-nav-item"><a href="/en-US/advertising">Advertise with us</a></li></ul></div><div class="page-footer-nav-col-2"><h2 class="footer-nav-heading">Support</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="https://support.mozilla.org/products/mdn-plus">Product help</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/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 width="112" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><title id="mozilla-footer-logo-svg">Mozilla logo</title><path d="M41.753 14.218c-2.048 0-3.324 1.522-3.324 4.157 0 2.423 1.119 4.286 3.29 4.286 2.082 0 3.447-1.678 3.447-4.347 0-2.826-1.522-4.096-3.413-4.096Zm54.89 7.044c0 .901.437 1.618 1.645 1.618 1.427 0 2.949-1.024 3.044-3.352-.649-.095-1.365-.185-2.02-.185-1.426-.005-2.668.397-2.668 1.92Z" fill="currentColor"></path><path d="M0 0v32h111.908V0H0Zm32.56 25.426h-5.87v-7.884c0-2.423-.806-3.352-2.39-3.352-1.924 0-2.702 1.365-2.702 3.324v4.868h1.864v3.044h-5.864v-7.884c0-2.423-.806-3.352-2.39-3.352-1.924 0-2.702 1.365-2.702 3.324v4.868h2.669v3.044H6.642v-3.044h1.863v-7.918H6.642V11.42h5.864v2.11c.839-1.489 2.3-2.39 4.252-2.39 2.02 0 3.878.963 4.566 3.01.778-1.862 2.361-3.01 4.566-3.01 2.512 0 4.812 1.522 4.812 4.84v6.402h1.863v3.044h-.005Zm9.036.307c-4.314 0-7.296-2.635-7.296-7.106 0-4.096 2.484-7.481 7.514-7.481s7.481 3.38 7.481 7.29c0 4.472-3.228 7.297-7.699 7.297Zm22.578-.307H51.942l-.403-2.11 7.7-8.846h-4.376l-.621 2.17-2.888-.313.498-4.907h12.294l.313 2.11-7.767 8.852h4.533l.654-2.172 3.167.308-.872 4.908Zm7.99 0h-4.191v-5.03h4.19v5.03Zm0-8.976h-4.191v-5.03h4.19v5.03Zm2.618 8.976 6.054-21.358h3.945l-6.054 21.358h-3.945Zm8.136 0 6.048-21.358h3.945l-6.054 21.358h-3.939Zm21.486.307c-1.863 0-2.887-1.085-3.072-2.792-.805 1.427-2.232 2.792-4.498 2.792-2.02 0-4.314-1.085-4.314-4.006 0-3.447 3.323-4.253 6.518-4.253.778 0 1.584.034 2.3.124v-.465c0-1.427-.034-3.133-2.3-3.133-.84 0-1.488.061-2.143.402l-.453 1.578-3.195-.34.549-3.224c2.45-.996 3.692-1.27 5.992-1.27 3.01 0 5.556 1.55 5.556 4.75v6.083c0 .805.314 1.085.963 1.085.184 0 .375-.034.587-.095l.034 2.11a5.432 5.432 0 0 1-2.524.654Z" fill="currentColor"></path></svg></a><ul class="footer-moz-list"><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Website Privacy Notice</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/#cookies" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Cookies</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/legal/terms/mozilla" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Legal</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/governance/policies/participation/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Community Participation Guidelines</a></li></ul></div><div class="page-footer-legal"><p id="license" class="page-footer-legal-text">Visit<!-- --> <a href="https://www.mozilla.org" target="_blank" rel="noopener noreferrer">Mozilla Corporation’s</a> <!-- -->not-for-profit parent, the<!-- --> <a target="_blank" rel="noopener noreferrer" href="https://foundation.mozilla.org/">Mozilla Foundation</a>.<br/>Portions of this content are ©1998–<!-- -->2024<!-- --> by individual mozilla.org contributors. Content available under<!-- --> <a href="/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/JavaScript/Client-side_web_APIs/Client-side_storage","doc":{"isMarkdown":true,"isTranslated":true,"isActive":true,"flaws":{},"title":"Client-side storage","mdn_url":"/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage","locale":"de","native":"Deutsch","sidebarHTML":"<ol><li class=\"section\"><a href=\"/de/docs/Learn/Getting_started_with_the_web\">Komplette Anfänger beginnen hier!</a></li><li><details><summary>Erste Schritte mit dem Web</summary><ol><li><a href=\"/de/docs/Learn/Getting_started_with_the_web\">Einführung ins Web</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/Installing_basic_software\">Installation von grundlegender Software</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like\">Wie wird Ihre Website aussehen?</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/Dealing_with_files\">Umgang mit Dateien</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/HTML_basics\">HTML-Grundlagen</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/CSS_basics\">CSS-Grundlagen</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/JavaScript_basics\">JavaScript-Grundlagen</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/Publishing_your_website\">Veröffentlichung Ihrer Website</a></li><li><a href=\"/de/docs/Learn/Getting_started_with_the_web/How_the_Web_works\">Wie das Web funktioniert</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/HTML\">HTML — Strukturierung des Webs</a></li><li><details><summary>Einführung in HTML</summary><ol><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML\">Einführung in HTML</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Getting_started\">Erste Schritte mit HTML</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML\">Was ist im Kopfbereich? Metadaten in HTML</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals\">Grundlagen des HTML-Textes</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks\">Erstellen von Hyperlinks</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting\">Erweiterte Textformatierung</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure\">Struktur eines Dokuments und einer Website</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML\">Debugging HTML</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter\">Markierung eines Briefes</a></li><li><a href=\"/de/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content\">Die Strukturierung einer Seite mit Inhalt</a></li></ol></details></li><li><details><summary>Multimedia und Einbettung</summary><ol><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding\">Multimedia und Einbettung</a></li><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML\">Bilder in HTML</a></li><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content\">Video- und Audioinhalte</a></li><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies\">Von Objekt zu iframe — andere Einbettungstechnologien</a></li><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web\">Vektorgrafiken zum Web hinzufügen</a></li><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images\">Responsive Images</a></li><li><a href=\"/de/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page\">Mozilla Splash-Seite</a></li></ol></details></li><li><details><summary>HTML-Tabellen</summary><ol><li><a href=\"/de/docs/Learn/HTML/Tables\">HTML-Tabellen</a></li><li><a href=\"/de/docs/Learn/HTML/Tables/Basics\">HTML Table Grundlagen</a></li><li><a href=\"/de/docs/Learn/HTML/Tables/Advanced\">Erweiterte Funktionen und Barrierefreiheit von HTML-Tabellen</a></li><li><a href=\"/de/docs/Learn/HTML/Tables/Structuring_planet_data\">Strukturierung von Planeten-Daten</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/CSS\">CSS — Gestaltung des Webs</a></li><li><details><summary>CSS erste Schritte</summary><ol><li><a href=\"/de/docs/Learn/CSS/First_steps\">Erste Schritte mit CSS</a></li><li><a href=\"/de/docs/Learn/CSS/First_steps/What_is_CSS\">Was ist CSS?</a></li><li><a href=\"/de/docs/Learn/CSS/First_steps/Getting_started\">Einstieg in CSS</a></li><li><a href=\"/de/docs/Learn/CSS/First_steps/How_CSS_is_structured\">Wie CSS strukturiert ist</a></li><li><a href=\"/de/docs/Learn/CSS/First_steps/How_CSS_works\">Wie CSS funktioniert</a></li><li><a href=\"/de/docs/Learn/CSS/First_steps/Styling_a_biography_page\">Eine Biografieseite stylen</a></li></ol></details></li><li><details><summary>CSS-Bausteine</summary><ol><li><a href=\"/de/docs/Learn/CSS/Building_blocks\">CSS-Grundbausteine</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Selectors\">CSS-Selektoren</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors\">Typ-, Klassen- und ID-Selektoren</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors\">Attributselektoren</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements\">Pseudo-Klassen und Pseudo-Elemente</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Selectors/Combinators\">Kombinatoren</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance\">Kaskade, Spezifität und Vererbung</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Cascade_layers\">Kaskadenschichten</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/The_box_model\">Das Boxmodell</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders\">Hintergründe und Rahmen</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Handling_different_text_directions\">Umgang mit unterschiedlichen Textausrichtungen</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Overflowing_content\">Überlaufender Inhalt</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Values_and_units\">CSS-Werte und Einheiten</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS\">Größe von Elementen in CSS</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Images_media_form_elements\">Bilder, Medien und Formularelemente</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Styling_tables\">Tabellen stylen</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Advanced_styling_effects\">Erweiterte Styling-Effekte</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Debugging_CSS\">Debugging CSS</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Organizing\">Organisieren Ihres CSS</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Fundamental_CSS_comprehension\">Grundlegendes CSS-Verständnis</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/Creating_fancy_letterheaded_paper\">Erstellen von stilvollem Briefpapier</a></li><li><a href=\"/de/docs/Learn/CSS/Building_blocks/A_cool_looking_box\">Eine cool aussehende Box</a></li></ol></details></li><li><details><summary>Textgestaltung</summary><ol><li><a href=\"/de/docs/Learn/CSS/Styling_text\">CSS Textgestaltung</a></li><li><a href=\"/de/docs/Learn/CSS/Styling_text/Fundamentals\">Grundlegende Text- und Schriftgestaltung</a></li><li><a href=\"/de/docs/Learn/CSS/Styling_text/Styling_lists\">Listen stilisieren</a></li><li><a href=\"/de/docs/Learn/CSS/Styling_text/Styling_links\">Styling von Links</a></li><li><a href=\"/de/docs/Learn/CSS/Styling_text/Web_fonts\">Web-Fonts</a></li><li><a href=\"/de/docs/Learn/CSS/Styling_text/Typesetting_a_homepage\">Setzen einer Community-Schul-Startseite</a></li></ol></details></li><li><details><summary>CSS-Layout</summary><ol><li><a href=\"/de/docs/Learn/CSS/CSS_layout\">CSS-Layout</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Introduction\">Einführung in CSS Layout</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Normal_Flow\">Normaler Fluss</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Flexbox\">Flexbox</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Grids\">Raster</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Floats\">Floats</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Positioning\">Positioning</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Multiple-column_Layout\">Mehrspaltiges Layout</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Responsive_Design\">Responsives Design</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Media_queries\">Einsteigerleitfaden für Media Queries</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods\">Legacy-Layout-Methoden</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers\">Unterstützung älterer Browser</a></li><li><a href=\"/de/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension\">Grundlegendes Verständnis von Layouts</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/JavaScript\">JavaScript — Dynamisches clientseitiges Skripting</a></li><li><details><summary>JavaScript erste Schritte</summary><ol><li><a href=\"/de/docs/Learn/JavaScript/First_steps\">JavaScript erste Schritte</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/What_is_JavaScript\">Was ist JavaScript?</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/A_first_splash\">Ein erster Sprung in JavaScript</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/What_went_wrong\">Was ist schiefgelaufen? JavaScript-Fehlerbehebung</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/Variables\">Speichern der benötigten Informationen — Variablen</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/Math\">Grundlegende Mathematik in JavaScript – Zahlen und Operatoren</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/Strings\">Umgang mit Text — Strings in JavaScript</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/Useful_string_methods\">Nützliche String-Methoden</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/Arrays\">Arrays</a></li><li><a href=\"/de/docs/Learn/JavaScript/First_steps/Silly_story_generator\">Silly Story Generator</a></li></ol></details></li><li><details><summary>JavaScript-Bausteine</summary><ol><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks\">JavaScript-Bausteine</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/conditionals\">Entscheidungen in Ihrem Code treffen — Bedingte Anweisungen</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Looping_code\">Schleifen-Code</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Functions\">Funktionen — wiederverwendbare Codeblöcke</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Build_your_own_function\">Erstellen Sie Ihre eigene Funktion</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Return_values\">Funktionsrückgabewerte</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Events\">Einführung in Ereignisse</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Event_bubbling\">Event bubbling</a></li><li><a href=\"/de/docs/Learn/JavaScript/Building_blocks/Image_gallery\">Bildgalerie</a></li></ol></details></li><li><details><summary>Einführung in JavaScript-Objekte</summary><ol><li><a href=\"/de/docs/Learn/JavaScript/Objects\">Einführung in JavaScript-Objekte</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/Basics\">JavaScript Objekt Grundlagen</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/Object_prototypes\">Objektprototypen</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/Object-oriented_programming\">Objektorientierte Programmierung</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/Classes_in_JavaScript\">Klassen in JavaScript</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/JSON\">Arbeiten mit JSON</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/Object_building_practice\">Objekt-Baupraxis</a></li><li><a href=\"/de/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features\">Hinzufügen von Funktionen zu unserem hüpfenden Kugeln-Demo</a></li></ol></details></li><li><details><summary>Asynchrones JavaScript</summary><ol><li><a href=\"/de/docs/Learn/JavaScript/Asynchronous\">Asynchrones JavaScript</a></li><li><a href=\"/de/docs/Learn/JavaScript/Asynchronous/Introducing\">Einführung in asynchrones JavaScript</a></li><li><a href=\"/de/docs/Learn/JavaScript/Asynchronous/Promises\">Anleitung zur Verwendung von Promises</a></li><li><a href=\"/de/docs/Learn/JavaScript/Asynchronous/Implementing_a_promise-based_API\">Anleitung zur Implementierung einer Promise-basierten API</a></li><li><a href=\"/de/docs/Learn/JavaScript/Asynchronous/Introducing_workers\">Einführung in Workers</a></li><li><a href=\"/de/docs/Learn/JavaScript/Asynchronous/Sequencing_animations\">Sequenzierung von Animationen</a></li></ol></details></li><li><details open=\"\"><summary>Client-seitige Web-APIs</summary><ol><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs\">Client-Side-Web-APIs</a></li><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Introduction\">Einführung in Web-APIs</a></li><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents\">Manipulating documents</a></li><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data\">Abrufen von Daten vom Server</a></li><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs\">Third-party APIs</a></li><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics\">Grafiken zeichnen</a></li><li><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs\">Video- und Audio-APIs</a></li><li><em><a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage\" aria-current=\"page\">Client-side storage</a></em></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/Forms\">Webformulare — Arbeiten mit Benutzerdaten</a></li><li><details><summary>Grundlagen der Webformulare</summary><ol><li><a href=\"/de/docs/Learn/Forms\">Bausteine für Webformulare</a></li><li><a href=\"/de/docs/Learn/Forms/Your_first_form\">Ihr erstes Formular</a></li><li><a href=\"/de/docs/Learn/Forms/How_to_structure_a_web_form\">Wie Sie ein Webformular strukturieren</a></li><li><a href=\"/de/docs/Learn/Forms/Basic_native_form_controls\">Basis-Native Formularelemente</a></li><li><a href=\"/de/docs/Learn/Forms/HTML5_input_types\">Die HTML5 input Typen</a></li><li><a href=\"/de/docs/Learn/Forms/Other_form_controls\">Andere Formularelemente</a></li><li><a href=\"/de/docs/Learn/Forms/Styling_web_forms\">Styling von Webformularen</a></li><li><a href=\"/de/docs/Learn/Forms/Advanced_form_styling\">Erweiterte Formular-Stilgestaltung</a></li><li><a href=\"/de/docs/Learn/Forms/UI_pseudo-classes\">UI-Pseudo-Klassen</a></li><li><a href=\"/de/docs/Learn/Forms/Form_validation\">Client-seitige Formularvalidierung</a></li><li><a href=\"/de/docs/Learn/Forms/Sending_and_retrieving_form_data\">Senden von Formulardaten</a></li></ol></details></li><li><details><summary>Erweiterte Techniken für Webformulare</summary><ol><li><a href=\"/de/docs/Learn/Forms/How_to_build_custom_form_controls\">Anleitung zur Erstellung benutzerdefinierter Formularelemente</a></li><li><a href=\"/de/docs/Learn/Forms/Sending_forms_through_JavaScript\">Versenden von Formularen über JavaScript</a></li><li><a href=\"/de/docs/Learn/Forms/Property_compatibility_table_for_form_controls\">CSS-Eigenschaftskompatibilitätstabelle für Formularelemente</a></li><li><a href=\"/de/docs/Learn/Forms/HTML_forms_in_legacy_browsers\">HTML-Formulare in älteren Browsern</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/Accessibility\">Barrierefreiheit — Das Web für alle nutzbar machen</a></li><li><details><summary>Barrierefreiheitsleitfäden</summary><ol><li><a href=\"/de/docs/Learn/Accessibility\">Barrierefreiheit</a></li><li><a href=\"/de/docs/Learn/Accessibility/What_is_accessibility\">Was ist Barrierefreiheit?</a></li><li><a href=\"/de/docs/Learn/Accessibility/HTML\">HTML: Eine gute Grundlage für Barrierefreiheit</a></li><li><a href=\"/de/docs/Learn/Accessibility/CSS_and_JavaScript\">CSS und JavaScript: Barrierefreiheits-Best Practices</a></li><li><a href=\"/de/docs/Learn/Accessibility/WAI-ARIA_basics\">Grundlagen von WAI-ARIA</a></li><li><a href=\"/de/docs/Learn/Accessibility/Multimedia\">Barrierefreie Multimedia</a></li><li><a href=\"/de/docs/Learn/Accessibility/Mobile\">Barrierefreiheit auf Mobilgeräten</a></li><li><a href=\"/de/docs/Learn/Accessibility/Accessibility_troubleshooting\">Bewertung: Barrierefreiheits-Troubleshooting</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/Performance\">Leistung — Websites schnell und reaktionsschnell machen</a></li><li><details><summary>Leitfäden zur Leistung</summary><ol><li><a href=\"/de/docs/Learn/Performance\">Webleistung</a></li><li><a href=\"/de/docs/Learn/Performance/why_web_performance\">Der 'Warum' der Web-Performance</a></li><li><a href=\"/de/docs/Learn/Performance/What_is_web_performance\">Was ist Web-Performance?</a></li><li><a href=\"/de/docs/Learn/Performance/Perceived_performance\">Wahrgenommene Leistung</a></li><li><a href=\"/de/docs/Learn/Performance/Measuring_performance\">Messung der Performance</a></li><li><a href=\"/de/docs/Learn/Performance/Multimedia\">Multimedia: Bilder</a></li><li><a href=\"/de/docs/Learn/Performance/video\">Multimedia: Video</a></li><li><a href=\"/de/docs/Learn/Performance/JavaScript\">JavaScript-Leistungsoptimierung</a></li><li><a href=\"/de/docs/Learn/Performance/HTML\">HTML-Leistungsoptimierung</a></li><li><a href=\"/de/docs/Learn/Performance/CSS\">CSS-Leistungsoptimierung</a></li><li><a href=\"/de/docs/Learn/Performance/business_case_for_performance\">Der geschäftliche Nutzen von Web-Performance</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/MathML\">MathML — Schreiben von Mathematik mit MathML</a></li><li><details><summary>MathML erste Schritte</summary><ol><li><a href=\"/de/docs/Learn/MathML/First_steps\">Erste Schritte mit MathML</a></li><li><a href=\"/de/docs/Learn/MathML/First_steps/Getting_started\">Erste Schritte mit MathML</a></li><li><a href=\"/de/docs/Learn/MathML/First_steps/Text_containers\">MathML Text-Container</a></li><li><a href=\"/de/docs/Learn/MathML/First_steps/Fractions_and_roots\">MathML-Brüche und -Wurzeln</a></li><li><a href=\"/de/docs/Learn/MathML/First_steps/Scripts\">MathML gescriptete Elemente</a></li><li><a href=\"/de/docs/Learn/MathML/First_steps/Tables\">MathML Tabellen</a></li><li><a href=\"/de/docs/Learn/MathML/First_steps/Three_famous_mathematical_formulas\">Drei berühmte mathematische Formeln</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/../Games\">Spiele — Entwicklung von Spielen für das Web</a></li><li><details><summary>Anleitungen und Tutorials</summary><ol><li><a href=\"/de/docs/Games/Introduction\">Einführung in die Spieleentwicklung für das Web</a></li><li><a href=\"/de/docs/Games/Techniques\">Techniken für die Spieleentwicklung</a></li><li><a href=\"/de/docs/Games/Tutorials\">Tutorials</a></li><li><a href=\"/de/docs/Games/Publishing_games\">Publishing Games</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/Tools_and_testing\">Werkzeuge und Tests</a></li><li><details><summary>Client-seitige Webentwicklungstools</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools\">Verständnis von Client-seitigen Webentwicklungstools</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview\">Übersicht über clientseitige Werkzeuge</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line\">Crashkurs zur Kommandozeile</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management\">Grundlagen des Paketmanagements</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Introducing_complete_toolchain\">Einführung in eine vollständige Toolchain</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Deployment\">Bereitstellung unserer App</a></li></ol></details></li><li><details><summary>Einführung in client-seitige Frameworks</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction\">Einführung in client-seitige Frameworks</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features\">Hauptmerkmale von Frameworks</a></li></ol></details></li><li><details><summary>React</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started\">Erste Schritte mit React</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning\">Beginn unserer React-Task-Liste</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components\">Komponentisieren unserer React-App</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state\">React-Interaktivität: Ereignisse und Status</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering\">React Interaktivität: Bearbeiten, Filtern, bedingtes Rendering</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility\">Accessibility in React</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources\">React-Ressourcen</a></li></ol></details></li><li><details><summary>Ember</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started\">Einstieg in Ember</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization\">Ember App-Struktur und Komponentisierung</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state\">Ember-Interaktivität: Events, Klassen und Zustand</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer\">Ember Interaktivität: Footer-Funktionalität, bedingtes Rendering</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing\">Routing in Ember</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources\">Ember-Ressourcen und Fehlerbehebung</a></li></ol></details></li><li><details><summary>Vue</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started\">Einstieg in Vue</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component\">Erstellen unserer ersten Vue-Komponente</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists\">Rendering einer Liste von Vue-Komponenten</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models\">Hinzufügen eines neuen Todo-Formulars: Vue-Ereignisse, Methoden und Modelle</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling\">Styling von Vue-Komponenten mit CSS</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties\">Verwendung von Vue computed properties</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering\">Vue bedingte Darstellung: Bearbeitung bestehender Todos</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management\">Vue-Refs und Lifecycle-Methoden zur Fokusverwaltung</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources\">Vue-Ressourcen</a></li></ol></details></li><li><details><summary>Svelte</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_getting_started\">Erste Schritte mit Svelte</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning\">Starten unserer Svelte-Tasklisten-App</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props\">Dynamisches Verhalten in Svelte: Arbeiten mit Variablen und Props</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components\">Komponentisierung unserer Svelte-App</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility\">Fortgeschrittenes Svelte: Reaktivität, Lebenszyklus, Barrierefreiheit</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores\">Arbeiten mit Svelte Stores</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript\">TypeScript-Unterstützung in Svelte</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next\">Bereitstellung und nächste Schritte</a></li></ol></details></li><li><details><summary>Angular</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_getting_started\">Erste Schritte mit Angular</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_todo_list_beginning\">Anfang unserer Angular-To-Do-Liste-App</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_styling\">Styling unserer Angular-Anwendung</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_item_component\">Erstellen einer Item-Komponente</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_filtering\">Filtern unserer To-Do-Elemente</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Angular_building\">Building Angular applications and further resources</a></li></ol></details></li><li><details><summary>Git und GitHub</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/GitHub\">Git und GitHub</a></li></ol></details></li><li><details><summary>Cross-Browser-Tests</summary><ol><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing\">Cross-Browser-Testing</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction\">Einführung in das Cross-Browser-Testing</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies\">Strategien zur Durchführung von Tests</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS\">Umgang mit häufigen HTML- und CSS-Problemen</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript\">Umgang mit häufigen JavaScript-Problemen</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility\">Umgang mit häufigen Problemen der Barrierefreiheit</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection\">Implementierung von Feature-Erkennung</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing\">Einführung in automatisiertes Testen</a></li><li><a href=\"/de/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment\">Einrichten Ihrer eigenen Testautomatisierungsumgebung</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/Server-side\">Server-seitige Webprogrammierung</a></li><li><details><summary>Erste Schritte</summary><ol><li><a href=\"/de/docs/Learn/Server-side/First_steps\">Server-seitige Website-Programmierung: Erste Schritte</a></li><li><a href=\"/de/docs/Learn/Server-side/First_steps/Introduction\">Einführung in die serverseitige Programmierung</a></li><li><a href=\"/de/docs/Learn/Server-side/First_steps/Client-Server_overview\">Überblick über Client-Server</a></li><li><a href=\"/de/docs/Learn/Server-side/First_steps/Web_frameworks\">Serverseitige Web-Frameworks</a></li><li><a href=\"/de/docs/Learn/Server-side/First_steps/Website_security\">Website-Sicherheit</a></li></ol></details></li><li><details><summary>Django Web-Framework (Python)</summary><ol><li><a href=\"/de/docs/Learn/Server-side/Django\">Django Web Framework (Python)</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Introduction\">Einführung in Django</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/development_environment\">Einrichten einer Django-Entwicklungsumgebung</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Tutorial_local_library_website\">Django-Tutorial: Die Local Library Website</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/skeleton_website\">Django-Tutorial Teil 2: Erstellung einer Skelett-Website</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Models\">Django-Tutorial Teil 3: Verwenden von Modellen</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Admin_site\">Django Tutorial Teil 4: Django Admin-Seite</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Home_page\">Django-Tutorial Teil 5: Erstellen unserer Startseite</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Generic_views\">Django Tutorial Teil 6: Generische Listen- und Detailansichten</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Sessions\">Django-Tutorial Teil 7: Sessions-Framework</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Authentication\">Django-Tutorial Teil 8: Benutzer-Authentifizierung und Berechtigungen</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Forms\">Django Tutorial Teil 9: Arbeiten mit Formularen</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Testing\">Django Tutorial Teil 10: Testen einer Django-Webanwendung</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/Deployment\">Django-Tutorial Teil 11: Django in Produktion bereitstellen</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/web_application_security\">Django-Webanwendungssicherheit</a></li><li><a href=\"/de/docs/Learn/Server-side/Django/django_assessment_blog\">Bewertung: DIY Django Mini-Blog</a></li></ol></details></li><li><details><summary>Express Web-Framework (Node.js/JavaScript)</summary><ol><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs\">Express-Webframework (Node.js/JavaScript)</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/Introduction\">Einführung in Express/Node</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/development_environment\">Einrichtung einer Node-Entwicklungsumgebung</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website\">Express-Tutorial: Die Website der lokalen Bibliothek</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/skeleton_website\">Express Tutorial Teil 2: Erstellung einer Grundstruktur für eine Website</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/mongoose\">Express Tutorial Teil 3: Verwendung einer Datenbank (mit Mongoose)</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/routes\">Express Tutorial Teil 4: Routen und Controller</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/Displaying_data\">Express Tutorial Teil 5: Bibliotheksdaten anzeigen</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/forms\">Express Tutorial Teil 6: Arbeiten mit Formularen</a></li><li><a href=\"/de/docs/Learn/Server-side/Express_Nodejs/deployment\">Express-Tutorial Teil 7: Bereitstellung für die Produktion</a></li></ol></details></li><li class=\"section\"><a href=\"/de/docs/Learn/Common_questions\">Weitere Ressourcen</a></li><li><details><summary>Häufige Fragen</summary><ol><li><a href=\"/de/docs/Learn/Common_questions\">Häufige Fragen</a></li><li><a href=\"/de/docs/Learn/HTML/Howto\">HTML verwenden, um häufige Probleme zu lösen</a></li><li><a href=\"/de/docs/Learn/CSS/Howto\">CSS verwenden, um häufige Probleme zu lösen</a></li><li><a href=\"/de/docs/Learn/JavaScript/Howto\">Lösen Sie häufige Probleme in Ihrem JavaScript-Code</a></li><li><a href=\"/de/docs/Learn/Common_questions/Web_mechanics\">Web-Mechanik</a></li><li><a href=\"/de/docs/Learn/Common_questions/Tools_and_setup\">Tools und Einrichtung</a></li><li><a href=\"/de/docs/Learn/Common_questions/Design_and_accessibility\">Design und Barrierefreiheit</a></li></ol></details></li></ol>","sidebarMacro":"LearnSidebar","body":[{"type":"prose","value":{"id":null,"title":null,"isH3":false,"content":"<ul class=\"prev-next\">\n <li><a class=\"button secondary\" href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs\"><span class=\"button-wrap\"> Zurück </span></a></li>\n <li><a class=\"button secondary\" href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs\"><span class=\"button-wrap\"> Übersicht: Client-Side-Web-APIs</span></a></li>\n \n</ul>\n<p>Moderne Webbrowser unterstützen verschiedene Methoden, um Daten auf dem Computer des Benutzers zu speichern – mit Zustimmung des Benutzers – und diese bei Bedarf wieder abzurufen. Dies ermöglicht es Ihnen, Daten für die langfristige Speicherung zu behalten, Websites oder Dokumente für die Offline-Nutzung zu speichern, benutzerspezifische Einstellungen für Ihre Website beizubehalten und vieles mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Methoden.</p>\n<figure class=\"table-container\"><table>\n <tbody>\n <tr>\n <th scope=\"row\">Voraussetzungen:</th>\n <td>\n JavaScript-Grundlagen (siehe\n <a href=\"/de/docs/Learn/JavaScript/First_steps\">Erste Schritte</a>,\n <a href=\"/de/docs/Learn/JavaScript/Building_blocks\">Bausteine</a>,\n <a href=\"/de/docs/Learn/JavaScript/Objects\">JavaScript-Objekte</a>),\n die\n <a href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Introduction\">Grundlagen der Client-seitigen APIs</a>\n </td>\n </tr>\n <tr>\n <th scope=\"row\">Ziel:</th>\n <td>Erlernen, wie man client-seitige Speicher-APIs verwendet, um Anwendungsdaten zu speichern.</td>\n </tr>\n </tbody>\n</table></figure>"}},{"type":"prose","value":{"id":"client-seitige_speicherung","title":"Client-seitige Speicherung?","isH3":false,"content":"<p>Andernorts im MDN-Lernbereich haben wir über den Unterschied zwischen <a href=\"/de/docs/Learn/Server-side/First_steps/Client-Server_overview#static_sites\">statischen Websites</a> und <a href=\"/de/docs/Learn/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 mit Hilfe einer Art Datenbank (serverseitige Speicherung) und führen <a href=\"/de/docs/Learn/Server-side\">serverseitigen</a> Code aus, um benötigte Daten abzurufen, in statische Seitentemplates einzufügen und das resultierende HTML an den Client zu senden, um es im Browser des Benutzers anzuzeigen.</p>\n<p>Die client-seitige Speicherung funktioniert nach ähnlichen Prinzipien, hat aber andere Anwendungsgebiete. Sie besteht aus JavaScript-APIs, die es ermöglichen, Daten auf dem Client (d. h. auf dem Rechner des Benutzers) zu speichern und bei Bedarf abzurufen. Dies hat viele verschiedene Anwendungen, wie z.B.:</p>\n<ul>\n <li>Personalisierung von Seiteneinstellungen (z. B. Anzeige von benutzerdefinierten Widgets, Farbschema oder Schriftgröße).</li>\n <li>Speichern von vorherigen Aktivitäten auf der Seite (z.B. Speichern des Inhalts eines Warenkorbs aus einer vorherigen Sitzung, Erinnern, ob ein Benutzer zuvor eingeloggt war).</li>\n <li>Speicherung von Daten und Ressourcen lokal, um eine schnellere (und möglicherweise kostengünstigere) Herunterladung zu ermöglichen oder eine Nutzung ohne Netzwerkverbindung zu erlauben.</li>\n <li>Speicherung von von Webanwendungen generierten Dokumenten zur Offline-Nutzung</li>\n</ul>\n<p>Oft werden client-seitige und serverseitige Speicher gemeinsam verwendet. Beispielsweise könnte man eine Reihe von Musikdateien herunterladen (vielleicht verwendet in einem Webspiel oder einer Musikplayer-Anwendung), diese in einer client-seitigen Datenbank speichern und bei Bedarf abspielen. Der Benutzer müsste 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> Es gibt Grenzen für die Menge an Daten, die Sie mit client-seitigen Speicher-APIs speichern können (möglicherweise sowohl pro einzelner API als auch kumulativ); das genaue Limit variiert je nach Browser und möglicherweise basierend auf Benutzereinstellungen. Weitere Informationen finden Sie unter <a href=\"/de/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria\">Browser Speicherquoten und Löschkriterien</a>.</p>\n</div>"}},{"type":"prose","value":{"id":"alte_schule_cookies","title":"Alte Schule: Cookies","isH3":true,"content":"<p>Das Konzept der client-seitigen Speicherung gibt es schon lange. Seit den frühen Tagen des Webs haben Websites <a href=\"/de/docs/Web/HTTP/Cookies\">Cookies</a> verwendet, um Informationen zu speichern, um die Benutzererfahrung auf Websites zu personalisieren. Sie sind die früheste Form von client-seitiger Speicherung, die im Web häufig genutzt wird.</p>\n<p>Heutzutage gibt es einfachere Mechanismen, um client-seitige Daten zu speichern, 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 immer noch häufig verwendet, um Daten zu speichern, die mit der Personalisierung und dem Zustand des Benutzers zusammenhängen, z. B. Sitzungs-IDs und Zugriffstoken. 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":"neue_schule_web_storage_und_indexeddb","title":"Neue Schule: 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 Datenobjekte, 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 Benutzers, ob er eingeloggt ist, welche Hintergrundfarbe verwendet werden soll usw.</li>\n <li>Die <a href=\"/de/docs/Web/API/IndexedDB_API\">IndexedDB API</a> bietet dem Browser ein vollständiges Datenbanksystem zum Speichern komplexer Daten. Dies kann für alles verwendet werden, von vollständigen Sätzen von Kundenunterlagen bis hin zu komplexen Datentypen wie Audio- oder Videodateien.</li>\n</ul>\n<p>Sie erfahren weiter unten mehr über diese APIs.</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 zum Speichern von HTTP-Antworten auf bestimmte Anfragen konzipiert und sehr nützlich für Dinge wie das Speichern von Website-Ressourcen offline, sodass die Website anschließend ohne Netzwerkverbindung genutzt werden kann. Cache wird normalerweise in Kombination mit der <a href=\"/de/docs/Web/API/Service_Worker_API\">Service Worker API</a> verwendet, obwohl es nicht zwingend erforderlich ist.</p>\n<p>Die Nutzung 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-speicherung_von_ressourcen\">Offline-Speicherung von Ressourcen</a> unten zeigen werden.</p>"}},{"type":"prose","value":{"id":"speicherung_einfacher_daten_—_web_storage","title":"Speicherung 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 Zeichenfolgen, 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>Gehen Sie zuerst zu unserer <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html\" class=\"external\" target=\"_blank\">Web Storage Blankovorlage</a> auf GitHub (öffnen Sie dies in einem neuen Tab).</p>\n </li>\n <li>\n <p>Öffnen Sie die JavaScript-Konsole der Entwickler-Tools Ihres Browsers.</p>\n </li>\n <li>\n <p>Alle Ihre Web Storage-Daten befinden sich in zwei objektartigen Strukturen innerhalb des Browsers: <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>. Der erste speichert Daten, solange der Browser geöffnet ist (die Daten gehen verloren, wenn der Browser geschlossen wird) und der zweite speichert Daten, auch nachdem der Browser geschlossen und dann erneut geöffnet wurde. Wir werden den zweiten in diesem Artikel verwenden, da er im Allgemeinen nützlicher ist.</p>\n <p>Die <a href=\"/de/docs/Web/API/Storage/setItem\"><code>Storage.setItem()</code></a>-Methode ermöglicht es Ihnen, einen Dateneintrag im Speicher zu speichern — sie erfordert zwei Parameter: den Namen des Eintrags und dessen 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 <a href=\"/de/docs/Web/API/Storage/getItem\"><code>Storage.getItem()</code></a>-Methode erfordert einen Parameter — den Namen eines Dateneintrags, den Sie abrufen möchten — und gibt den Wert dieses Eintrags 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> jetzt den Wert des <code>name</code>-Dateneintrags enthält.</p>\n </li>\n <li>\n <p>Die <a href=\"/de/docs/Web/API/Storage/removeItem\"><code>Storage.removeItem()</code></a>-Methode erfordert einen Parameter — den Namen eines Dateneintrags, den Sie entfernen möchten — und entfernt diesen Eintrag aus der Webspeicherung. 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 jetzt <code>null</code> zurückgeben — der <code>name</code>-Eintrag existiert nicht mehr in der Webspeicherung.</p>\n </li>\n</ol>"}},{"type":"prose","value":{"id":"die_daten_bleiben_erhalten!","title":"Die Daten bleiben erhalten!","isH3":true,"content":"<p>Ein wichtiges Merkmal der Webspeicherung ist, dass die Daten zwischen Seitenaufrufen (und sogar beim Herunterfahren des Browsers, im Fall von <code>localStorage</code>) bestehen bleiben. Schauen wir uns das in Aktion an.</p>\n<ol>\n <li>\n <p>Öffnen Sie unsere Web Storage Blankovorlage erneut, diesmal aber in einem anderen Browser als dem, in dem Sie dieses Tutorial geöffnet haben! Dies erleichtert den Umgang damit.</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 den zurückgegebenen Name-Eintrag sehen.</p>\n </li>\n <li>\n <p>Schließen Sie nun den Browser und öffnen Sie ihn erneut.</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 weiterhin verfügbar ist, auch nachdem der Browser geschlossen und dann erneut geöffnet wurde.</p>\n </li>\n</ol>"}},{"type":"prose","value":{"id":"getrennter_speicher_für_jede_domain","title":"Getrennter Speicher für jede Domain","isH3":true,"content":"<p>Es gibt einen separaten Datenspeicher für jede Domain (jede separate Webadresse, die im Browser geladen wird). Sie werden sehen, dass, wenn Sie zwei Websites laden (zum Beispiel google.com und amazon.com) und versuchen, einen Eintrag auf einer Website zu speichern, dieser auf der anderen Website nicht verfügbar ist.</p>\n<p>Dies ist sinnvoll – 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_komplexeres_beispiel","title":"Ein komplexeres Beispiel","isH3":true,"content":"<p>Lassen Sie uns dieses neu erworbene Wissen anwenden, indem wir ein funktionierendes Beispiel schreiben, um Ihnen eine Vorstellung davon zu geben, wie Webspeicherung verwendet werden kann. Unser Beispiel ermöglicht es Ihnen, einen Namen einzugeben, woraufhin die Seite so aktualisiert wird, dass Sie eine personalisierte Begrüßung erhalten. Dieser Zustand bleibt auch über Seiten-/Browser-Reloads hinweg bestehen, da der Name in der Webspeicherung gespeichert ist.</p>\n<p>Sie können 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> finden – dies enthält eine Website mit einem Header, Inhalt und Fußzeile sowie ein Formular zum Eingeben Ihres Namens.</p>\n<p>\n <img src=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage/web-storage-demo.png\" alt=\"Ein Screenshot einer Website mit Header-, Inhalts- und Fußzeile. Der Header hat links einen Begrüßungstext und rechts eine Schaltfläche mit der Bezeichnung 'Vergessen'. Der Inhalt hat eine Überschrift gefolgt von zwei Absätzen Blindtext. Die Fußzeile lautet 'Copyright nobody. Use the code as you like'.\" width=\"1024\" height=\"550\" loading=\"lazy\">\n</p>\n<p>Lassen Sie uns das Beispiel aufbauen, damit Sie verstehen, wie es funktioniert.</p>\n<ol>\n <li>\n <p>Erstellen Sie zunächst 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>. Wir müssen diese erstellen und unseren JavaScript-Code hineinschreiben. 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, Verweise auf alle HTML-Funktionen zu erstellen, die wir in diesem Beispiel manipulieren müssen – wir werden sie alle als Konstanten erstellen, da diese Verweise im Lebenszyklus der App nicht geändert werden 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 einbinden, um zu verhindern, dass das Formular sich tatsächlich selbst abschickt, wenn die Absenden-Schaltfläche gedrückt wird, da dies nicht das gewünschte Verhalten ist. Fügen Sie das folgende 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>Jetzt müssen wir einen Ereignis-Listener hinzufügen, dessen Handlerfunktion ausgeführt wird, wenn die Schaltfläche „Sag Hallo“ geklickt wird. Die Kommentare erläutern im Detail, was jeder Teil tut, aber im Wesentlichen nehmen wir hier den Namen, den der Benutzer in das Texteingabefeld eingegeben hat, speichern ihn in der Webspeicherung mit <code>setItem()</code> und führen dann eine Funktion namens <code>nameDisplayCheck()</code> aus, die das Aktualisieren des tatsächlichen Website-Textes übernimmt. Fügen Sie dies 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>// 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 dieser Stelle benötigen wir auch einen Ereignis-Handler, der eine Funktion ausführt, wenn die Schaltfläche „Vergessen“ geklickt wird – diese wird nur angezeigt, nachdem die Schaltfläche „Sag Hallo“ geklickt wurde (die beiden Formularzustände wechseln hin und her). In dieser Funktion entfernen wir den <code>name</code>-Eintrag aus der Webspeicherung mit <code>removeItem()</code> und führen dann erneut <code>nameDisplayCheck()</code> aus, um das Display 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>Es ist nun an der Zeit, die <code>nameDisplayCheck()</code>-Funktion selbst zu definieren. Hier überprüfen wir, ob der Namenseintrag in der Webspeicherung gespeichert wurde, indem wir <code>localStorage.getItem('name')</code> als bedingten Test verwenden. Wenn der Name gespeichert wurde, wird dieser Aufruf als <code>true</code> ausgewertet; wenn nicht, wird der Aufruf als <code>false</code> ausgewertet. Wenn der Aufruf als <code>true</code> ausgewertet wird, zeigen wir eine personalisierte Begrüßung an, zeigen den „Vergessen“-Teil des Formulars an und verbergen den „Sag Hallo“-Teil des Formulars. Wenn der Aufruf als <code>false</code> ausgewertet wird, zeigen wir eine generische Begrüßung an und verhalten uns umgekehrt. Fügen Sie den folgenden Code 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>// 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 <code>nameDisplayCheck()</code>-Funktion ausführen, wenn die Seite geladen wird. Wenn wir dies nicht tun, dann würde die personalisierte Begrüßung nicht über Seitenreloads 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 bleibt, ist Ihr 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\">abgeschlossene Version hier live sehen</a>.</p>\n<div class=\"notecard note\">\n <p><strong>Hinweis:</strong> Es gibt ein weiteres, etwas komplexeres Beispiel, das Sie in <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> In der Zeile <code><script src=\"index.js\" defer></script></code> des Quellcodes unserer abgeschlossenen 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 vollständig geladen ist.</p>\n</div>"}},{"type":"prose","value":{"id":"speicherung_komplexer_daten_—_indexeddb","title":"Speicherung komplexer Daten — IndexedDB","isH3":false,"content":"<p>Die <a href=\"/de/docs/Web/API/IndexedDB_API\">IndexedDB API</a> (manchmal als IDB abgekürzt) ist ein komplettes Datenbanksystem, das im Browser verfügbar ist, in dem Sie komplexe zusammenhängende Daten speichern können, deren Typen nicht auf einfache Werte wie Zeichenfolgen oder Zahlen beschränkt sind. Sie können Videos, Bilder und so ziemlich alles andere in einer IndexedDB-Instanz speichern.</p>\n<p>\n Die IndexedDB API erlaubt es Ihnen, eine Datenbank zu erstellen und dann „object stores“ in dieser Datenbank zu erstellen.\n „Object stores“ sind wie Tabellen in einer relationalen Datenbank, und jeder „object store“ kann eine Anzahl von Objekten enthalten.\n Um mehr über die IndexedDB API zu erfahren, siehe <a href=\"/de/docs/Web/API/IndexedDB_API/Using_IndexedDB\">Verwendung von IndexedDB</a>.\n</p>\n<p>Allerdings ist dies mit Kosten verbunden: IndexedDB ist viel komplexer zu verwenden als die Web Storage API. In diesem Abschnitt werden wir nur an der Oberfläche dessen kratzen, wozu es fähig ist, aber wir werden Ihnen genug geben, um anzufangen.</p>"}},{"type":"prose","value":{"id":"durcharbeiten_eines_notizen-speicherbeispiels","title":"Durcharbeiten eines Notizen-Speicherbeispiels","isH3":true,"content":"<p>Hier führen wir Sie Schritt für Schritt durch ein Beispiel, das es Ihnen ermöglicht, Notizen in Ihrem Browser zu speichern und sie wann immer Sie möchten anzuzeigen und zu löschen, und erklären die grundlegendsten Teile von IDB, während wir es zusammen aufbauen.</p>\n<p>Die App sieht in etwa so aus:</p>\n<p>\n <img src=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage/idb-demo.png\" alt=\"Ein IndexDB Notizen-Demo-Screenshot mit 4 Abschnitten. Der erste Abschnitt ist der Header. Der zweite Abschnitt listet alle Notizen auf, die erstellt wurden. Es hat zwei Notizen, jede mit einem Löschen-Button. Ein dritter Abschnitt ist ein Formular mit 2 Eingabefeldern für 'Notiztitel' und 'Notiztext' und einem Knopf mit der Aufschrift 'Neue Notiz erstellen'. Der untere Abschnitt Fußzeile liest 'Copyright nobody. Use the code as you like'.\" width=\"803\" height=\"736\" loading=\"lazy\">\n</p>\n<p>Jede Notiz hat einen Titel und einen Textkörper, die individuell bearbeitet werden können. Der JavaScript-Code, den wir im Folgenden durchgehen werden, enthält detaillierte Kommentare, um Ihnen beim Verständnis zu helfen.</p>"}},{"type":"prose","value":{"id":"erste_schritte","title":"Erste Schritte","isH3":true,"content":"<ol>\n <li>Erstellen Sie zuerst 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 Ihrem lokalen Rechner.</li>\n <li>Schauen Sie sich die Dateien an. Sie werden sehen, dass das HTML eine Website mit einem Header und einer Fußzeile sowie einem Hauptinhaltbereich definiert, der einen Platz zum Anzeigen von Notizen und ein Formular zum Eingeben neuer Notizen in die Datenbank enthält. Das CSS bietet einige Stile, um zu verdeutlichen, 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, sowie auf das Titel- und Körper-<a href=\"/de/docs/Web/HTML/Element/input\"><code><input></code></a> Elemente, das <a href=\"/de/docs/Web/HTML/Element/form\"><code><form></code></a> selbst und den <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 nun bereit, Code darin hinzuzufügen.</li>\n</ol>"}},{"type":"prose","value":{"id":"initiale_datenbankeinrichtung","title":"Initiale Datenbankeinrichtung","isH3":true,"content":"<p>Schauen wir uns jetzt an, was wir tun müssen, um eigentlich 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 darzustellen, das unsere Datenbank repräsentiert. Wir werden dies an einigen Stellen verwenden, daher haben wir es global hier deklariert, um die Dinge zu vereinfachen.</p>\n </li>\n <li>\n <p>Als Nächstes fügen Sie Folgendes 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, um Version <code>1</code> einer Datenbank namens <code>notes_db</code> zu öffnen. Wenn diese nicht bereits existiert, wird sie von anschließendem Code für Sie erstellt. Sie werden dieses Anforderungsmuster sehr oft in der IndexedDB sehen. Datenbankoperationen benötigen Zeit. Sie möchten den Browser nicht einfrieren, während Sie auf die Ergebnisse warten, daher sind Datenbankoperationen <a href=\"/de/docs/Glossary/Asynchronous\">asynchron</a>, d.h. sie geschehen nicht sofort, sondern irgendwann in der Zukunft, und Sie werden benachrichtigt, wenn sie fertig sind.</p>\n <p>Um dies in IndexedDB zu handhaben, erstellen Sie ein Anforderungsobjekt (das Sie nach Belieben benennen können – wir haben es hier <code>openRequest</code> genannt, damit es obvious ist, wofür es ist). Sie verwenden dann Ereignis-Handler, um Code auszuführen, wenn die Anfrage abschließt, fehlschlägt usw., was Sie weiter unten in Aktion sehen werden.</p>\n <div class=\"notecard note\">\n <p><strong>Hinweis:</strong> Die Versionsnummer ist wichtig. Wenn Sie Ihre Datenbank aktualisieren möchten (zum Beispiel durch Ändern der Tabellenstruktur), müssen Sie Ihren Code erneut ausführen, jedoch mit einer erhöhten Versionsnummer und einem im <code>upgradeneeded</code>-Handler (siehe unten) spezifizierten abweichenden Schema usw. Wir werden das Upgrade 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 Ihrem vorherigen Hinzufügung ein:</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. Dies ermöglicht es Ihnen, auf dieses Problem zu 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 Anfrage erfolgreich zurückkehrt, 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 gemacht, 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 es jetzt aus, damit die Notizen, die sich bereits in der Datenbank befinden, angezeigt werden, sobald die Seite geladen wird. Sie werden <code>displayData()</code> später definiert sehen.</p>\n </li>\n <li>\n <p>Schließlich für diesen Abschnitt fügen wir wahrscheinlich den wichtigsten Ereignis-Handler für die 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 größeren Versionsnummer als die bestehende gespeicherte Datenbank geöffnet wird (bei Durchführung eines Upgrades). 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 (Struktur) unserer Datenbank; das heißt die Menge an Spalten (oder Feldern), die sie enthält. Hier greifen wir zuerst auf eine Referenz zur bestehenden Datenbank aus der <code>result</code>-Eigenschaft des Ziels des Ereignisses (<code>e.target.result</code>) zu, welches das Anforderungsobjekt ist. Dies entspricht der Zeile <code>db = openRequest.result;</code> innerhalb des <code>success</code>-Ereignis-Handlers, aber wir müssen dies hier separat tun, da der <code>upgradeneeded</code>-Ereignis-Handler (falls benötigt) 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>Dann verwenden wir <a href=\"/de/docs/Web/API/IDBDatabase/createObjectStore\"><code>IDBDatabase.createObjectStore()</code></a>, um ein neues Objekt-Lager in unserer geöffneten Datenbank zu erstellen, das <code>notes_os</code> genannt wird. Dies entspricht einer einzelnen Tabelle in einem konventionellen Datenbanksystem. Wir haben ihm den Namen Notizen gegeben und auch ein <code>autoIncrement</code>-Schlüsselfeld namens <code>id</code> spezifiziert – in jedem neuen Datensatz wird diesem automatisch ein inkrementierter Wert gegeben – der Entwickler muss dies nicht explizit setzen. Als Schlüssel wird das <code>id</code>-Feld verwendet, um Datensätze eindeutig zu identifizieren, etwa beim Löschen oder Anzeigen eines Datensatzes.</p>\n <p>Wir erstellen auch zwei andere Indizes (Felder) mit der Methode <a href=\"/de/docs/Web/API/IDBObjectStore/createIndex\"><code>IDBObjectStore.createIndex()</code></a>: <code>title</code> (welcher einen Titel für jede Notiz enthält) und <code>body</code> (welcher den Textinhalt der Notiz enthält).</p>\n </li>\n</ol>\n<p>So mit diesem Datenbankschema, wenn wir anfangen, Datensätze in die Datenbank einzufügen, wird jeder als ein Objekt in folgender Struktur 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 in die Datenbank hinzufügen können. Dies geschieht mit dem Formular auf unserer Seite.</p>\n<p>Unter Ihrem vorherigen Ereignis-Handler fügen Sie die folgende Zeile hinzu, die einen <code>submit</code>-Ereignis-Handler einrichtet, der eine Funktion namens <code>addData()</code> ausführt, wenn das Formular übermittelt 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>Lassen Sie uns nun die <code>addData()</code>-Funktion definieren. Fügen Sie dies 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; unterteilt gesagt, wir:</p>\n<ul>\n <li>Führen <a href=\"/de/docs/Web/API/Event/preventDefault\"><code>Event.preventDefault()</code></a> am Ereignisobjekt aus, um zu verhindern, dass das Formular tatsächlich auf die konventionelle Art übermittelt wird (dies würde ein Seitenrefresh verursachen und das Erlebnis verderben).</li>\n <li>Erstellen ein Objekt, das einen Datensatz darstellt, der in die Datenbank eingegeben werden soll, und füllen es mit Werten aus den Formulareingaben. Beachten Sie, dass wir keinen <code>id</code>-Wert explizit einfügen müssen – wie bereits erläutert, wird dieser automatisch gefüllt.</li>\n <li>Öffnen eine <code>readwrite</code>-Transaktion gegen das <code>notes_os</code> Objekt-Store mit der <a href=\"/de/docs/Web/API/IDBDatabase/transaction\"><code>IDBDatabase.transaction()</code></a>-Methode. Dieses Transaktionsobjekt erlaubt uns den Zugriff auf das Objekt-Store, sodass wir etwas damit tun können, z. B. einen neuen Datensatz hinzufügen.</li>\n <li>Greifen auf das Objekt-Lager mit der <a href=\"/de/docs/Web/API/IDBTransaction/objectStore\"><code>IDBTransaction.objectStore()</code></a>-Methode zu und speichern das Ergebnis in der Variablen <code>objectStore</code>.</li>\n <li>Fügen den neuen Datensatz mit <a href=\"/de/docs/Web/API/IDBObjectStore/add\"><code>IDBObjectStore.add()</code></a> in die Datenbank ein. Dies erstellt ein Anforderungsobjekt, in der gleichen Art und Weise, wie wir es vorher gesehen haben.</li>\n <li>Fügen eine Reihe von Ereignis-Handler am <code>request</code>- und <code>transaction</code>-Objekt hinzu, um Code an kritischen Punkten im Lebenszyklus auszuführen. Sobald die Anfrage erfolgreich abgeschlossen ist, leeren wir die Formulareingaben, um die Eingabe der nächsten Notiz vorzubereiten. 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 besser 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>Erneut, brechen wir dies herunter:</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 Sie am Ende eine riesige Liste von duplizierten Inhalten erhalten, die bei jeder Aktualisierung hinzugefügt wird.</li>\n <li>Als nächstes bekommen wir eine Referenz zum <code>notes_os</code>-Objekt-Store mittels <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> wie wir es in <code>addData()</code> gemacht haben, außer dass wir sie hier in einer Zeile verketten.</li>\n <li>Der nächste Schritt ist die Verwendung der <a href=\"/de/docs/Web/API/IDBObjectStore/openCursor\"><code>IDBObjectStore.openCursor()</code></a>-Methode, um eine Anfrage für einen Cursor zu öffnen – das ist ein Konstrukt, das verwendet werden kann, um die Datensätze in einem Object-Store zu durchlaufen. Wir verketten einen <code>success</code>-Ereignis-Handler an das Ende dieser Zeile, um den Code prägnanter zu machen – wenn der Cursor erfolgreich zurückgegeben wird, wird der Handler ausgeführt.</li>\n <li>Wir bekommen 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 überprüfen wir, ob der Cursor einen Datensatz aus dem Datenspeicher enthält (<code>if (cursor){ }</code>) – falls ja, erstellen wir ein 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 geklickt, diese Notiz mit 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 bewegen und den Inhalt des <code>if</code>-Blocks erneut auszuführen. Wenn es einen weiteren Datensatz gibt, zu dem iteriert wird, wird dies bewirken, dass er in die Seite eingefügt wird, und dann wird <code>continue()</code> erneut ausgeführt, und so weiter.</li>\n <li>Wenn es keine weiteren Datensätze mehr gibt, zu denen iteriert werden kann, wird <code>cursor</code> <code>undefined</code> zurückgeben, und somit wird der <code>else</code>-Block anstelle des <code>if</code>-Blocks ausgeführt. Dieser Block überprüft, ob keine Notizen in das <code><ul></code> eingefügt wurden – falls nicht, wird eine Nachricht eingefügt, die sagt, dass keine Notiz gespeichert wurde.</li>\n</ul>"}},{"type":"prose","value":{"id":"löschen_einer_notiz","title":"Löschen einer Notiz","isH3":true,"content":"<p>Wie oben erwähnt, wird eine Notiz gelöscht, wenn der Löschen-Button der Notiz gedrückt wird. Dies wird durch die <code>deleteItem()</code>-Funktion erreicht, die wie folgt aussieht:</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 hiervon könnte eine Erklärung benötigen – wir rufen die ID des zu löschenden Datensatzes über <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> ab – erinnern Sie sich, dass die ID des Datensatzes bei der ersten Anzeige in einem <code>data-note-id</code>-Attribut bei den <code><li></code> gespeichert wurde. Wir müssen das Attribut jedoch über das globale eingebaute <a href=\"/de/docs/Web/JavaScript/Reference/Global_Objects/Number\"><code>Number()</code></a>-Objekt verarbeiten, da es vom Datentyp <code>string</code> ist und daher von der Datenbank, die eine Zahl erwartet, nicht erkannt werden würde.</li>\n <li>Anschließend erhalten wir über das uns bereits bekannte Muster eine Referenz zum Objekt-Store 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, indem wir ihm die ID übergeben.</li>\n <li>Wenn die Datenbank-Transaktion abgeschlossen ist, löschen wir die Notiz-<code><li></code> aus dem DOM und führen erneut die Überprüfung durch, um zu sehen, ob das <code><ul></code> jetzt leer ist, und fügen bei Bedarf eine Notiz ein.</li>\n</ul>\n<p>Das ist alles! Ihr Beispiel sollte nun funktionieren.</p>\n<p>Wenn Sie Schwierigkeiten damit haben, <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/\" class=\"external\" target=\"_blank\">können Sie es gerne mit unserem Live-Beispiel 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":"speicherung_komplexer_daten_über_indexeddb","title":"Speicherung komplexer Daten über IndexedDB","isH3":true,"content":"<p>Wie bereits 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 Bild-Blobs. Und es ist nicht viel schwieriger als andere Datentypen.</p>\n<p>Um zu zeigen, wie es 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 Videoladen</a> geschrieben (siehe es auch <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/\" class=\"external\" target=\"_blank\">hier live laufen</a>). Beim ersten Ausführen des Beispiels lädt es alle Videos vom Netzwerk herunter, speichert sie in einer IndexedDB-Datenbank und zeigt die Videos dann in der UI innerhalb von <a href=\"/de/docs/Web/HTML/Element/video\"><code><video></code></a>-Elementen an. Beim zweiten Ausführen findet es die Videos in der Datenbank und ruft sie von dort ab, bevor es sie anzeigt – das macht die nachfolgenden Ladezeiten viel schneller und weniger bandbreitenlastig.</p>\n<p>Schauen wir uns die interessantesten Teile des Beispiels an. Wir werden nicht alles durchgehen – vieles davon ist dem vorherigen Beispiel ähnlich, 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>Zu Beginn, 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 Datenbank <code>videos</code> zu laden.</p>\n <p>Wenn jedes Video in der Datenbank gefunden wird (überprüft durch Prüfen, ob <code>request.result</code> als <code>true</code> auswertet – wenn der Datensatz nicht vorhanden ist, wird er <code>undefined</code> sein), werden die Videosdateien (als Blobs gespeichert) und der Videoname direkt an die <code>displayVideo()</code>-Funktion weitergegeben, um sie in der UI zu platzieren. Andernfalls wird der Videoname an die Funktion <code>fetchVideoFromNetwork()</code> übergeben, um, Sie haben es erraten, das Video aus dem Netzwerk abzurufen.</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>Der folgende Schnipsel stammt aus der Funktion <code>fetchVideoFromNetwork()</code> – hier holen wir MPEG-4- und WebM-Versionen des Videos über zwei separate <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 und uns eine Objekt-Darstellung der Videos zu geben, die später gespeichert und angezeigt werden kann.</p>\n <p>Hier haben wir jedoch ein Problem – diese beiden Anfragen sind asynchron, aber wir möchten die Videos nur dann anzeigen oder speichern, wenn beide Zusagen erfüllt sind. Glücklicherweise gibt es eine eingebaute Methode, die ein solches Problem behandelt – <a href=\"/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/all\"><code>Promise.all()</code></a>. Diese nimmt ein Argument – Referenzen zu all den einzelnen Zusagen, die Sie auf Erfüllung prüfen möchten, in einem Array abgelegt – und gibt eine Zusage zurück, die erfüllt wird, wenn alle Einzelzusagen erfüllt sind.</p>\n <p>Im <code>then()</code>-Handler für diese Zusage rufen wir die Funktion <code>displayVideo()</code> auf, wie wir es zuvor getan haben, um die Videos in der UI anzuzeigen, und rufen dann 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 zum Hinzufügen von Daten zur Datenbank gesehen haben, sehr ähnlich – wir öffnen eine <code>readwrite</code>-Transaktion und erhalten eine Referenz zu unserem <code>videos_os</code>-Objekt-Store, erstellen ein Objekt, das den Datensatz darstellt, der zur Datenbank hinzugefügt werden soll, 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 UI einzufügen, und sie dann zur Seite hinzufügt. Die interessantesten Teile davon sind die unten gezeigten – um unsere Videoblobs tatsächlich in einem <code><video></code>-Element anzuzeigen, müssen wir Objekt-URLs erstellen (interne URLs, die auf die in Erinnerung gespeicherten Videoblobs verweisen) mit der Methode <a href=\"/de/docs/Web/API/URL/createObjectURL_static\"><code>URL.createObjectURL()</code></a>. Sobald dies geschehen ist, können wir die Objekt-URLs als Werte unserer <code>src</code>-Attribute des <a href=\"/de/docs/Web/HTML/Element/source\"><code><source></code></a>-Elements 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-speicherung_von_ressourcen","title":"Offline-Speicherung von Ressourcen","isH3":false,"content":"<p>Das obige Beispiel zeigt bereits, wie man eine App erstellt, die große Ressourcen in einer IndexedDB-Datenbank speichert und so das Herunterladen mehr als einmal vermeidet. Dies ist bereits eine große Verbesserung der Benutzererfahrung, aber es fehlt noch eine Sache – die Haupt-HTML-, CSS- und JavaScript-Dateien müssen immer noch jedes Mal heruntergeladen werden, wenn die Seite aufgerufen wird, was bedeutet, dass sie nicht funktioniert, wenn keine Netzwerkverbindung besteht.</p>\n<p>\n <img src=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage/ff-offline.png\" alt=\"Firefox-Offline-Bildschirm mit einer Abbildung einer Cartoon-Figur auf der linken Seite, die mit der rechten Hand einen zwei-poligen Stecker und mit der linken Hand eine zwei-polige Steckdose hält. Auf der rechten Seite gibt es eine Offline-Modus-Nachricht und einen Button mit der Aufschrift 'Erneut versuchen'.\" width=\"765\" height=\"307\" loading=\"lazy\">\n</p>\n<p>Hier kommen <a href=\"/de/docs/Web/API/Service_Worker_API\">Service Worker</a> und die verwandte <a href=\"/de/docs/Web/API/Cache\">Cache API</a> ins Spiel.</p>\n<p>Ein Service Worker ist eine JavaScript-Datei, die beim Zugriff durch einen Browser gegen eine bestimmte Herkunft (Website oder einen Teil einer Website auf einer bestimmten Domain) registriert wird. Wenn er registriert ist, kann er Seiten an dieser Herkunft kontrollieren. Er tut dies, indem er zwischen einer geladenen Seite und dem Netzwerk sitzt und Netzwerkanfragen abfängt, die an diese Herkunft gerichtet sind.</p>\n<p>Wenn er eine Anfrage abfängt, kann er alles damit machen, was Sie wollen (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 dann das Bereitstellen dieser als Antwort auf eine Anfrage anstelle der Antworten aus dem Netzwerk. Tatsächlich erlaubt es, eine Website komplett offline arbeiten zu lassen.</p>\n<p>Die Cache-API ist ein weiteres client-seitiges Speichermechanismus, mit einem kleinen Unterschied – sie ist darauf 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 dies aussehen könnte. Wir haben eine weitere Version des Video Store-Beispiels erstellt, das wir im vorherigen Abschnitt gesehen haben – dies funktioniert identisch, außer dass es auch die HTML-, CSS- und JavaScript-Dateien in der Cache-API über einen Service Worker speichert und das Beispiel offline laufen lässt!</p>\n<p>Siehe <a href=\"https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/\" class=\"external\" target=\"_blank\">IndexedDB Videoladen mit Service Worker live laufen</a>, und sehen Sie auch den <a href=\"https://github.com/mdn/learning-area/tree/main/javascript/apis/client-side-storage/cache-sw/video-store-offline\" class=\"external\" target=\"_blank\">Quellcode</a>.</p>\n<h4 id=\"registrierung_des_service_workers\">Registrierung des Service Workers</h4>\n<p>Das erste, was zu beachten ist, ist, dass es ein zusätzliches Stück Code 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>). Wir führen zuerst einen Feature-Erkennungstest durch, um zu sehen, ob das <code>serviceWorker</code>-Mitglied im <a href=\"/de/docs/Web/API/Navigator\"><code>Navigator</code></a> vorhanden ist. Wenn das <code>true</code> zurückgibt, dann wissen wir, dass zumindest die Grundlagen der Service Worker unterstützt werden. Innerhalb hier verwenden wir die Methode <a href=\"/de/docs/Web/API/ServiceWorkerContainer/register\"><code>ServiceWorkerContainer.register()</code></a>, um einen Service Worker, der in der Datei <code>sw.js</code> enthalten ist, gegen die Herkunft, an der er sich befindet, zu registrieren, sodass er Seiten im selben Verzeichnis wie er oder Unterverzeichnissen kontrollieren kann. Wenn Ihr 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> Der angegebene Pfad zur <code>sw.js</code>-Datei ist relativ zur Ursprungsseite, nicht zur JavaScript-Datei, die den Code enthält. Der Service Worker befindet sich unter <code>https://mdn.github.io/learning-area/javascript/apis/player-cache-sw/video-store-offline/sw.js</code>. Die Ursprungsseite ist <code>https://mdn.github.io</code>, und daher muss der angegebene Pfad <code>/learning-area/javascript/apis/player-cache-sw/video-store-offline/sw.js</code> sein. Wenn Sie dieses Beispiel auf Ihrem eigenen Server hosten möchten, müssen Sie dies entsprechend ändern. Dies ist etwas 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>Beim nächsten Mal, wenn eine Seite unter der Kontrolle des Service Workers aufgerufen wird (z.B. beim Hinweis des Beispiels), wird der Service Worker gegen diese Seite installiert, was bedeutet, dass er beginnt, sie zu kontrollieren. Wenn dies geschieht, wird ein <code>install</code>-Ereignis gegen den Service Worker ausgelöst; Sie können Code innerhalb des Service Workers selbst schreiben, der auf die Installation reagiert.</p>\n<p>Schauen wir uns ein Beispiel an, in der Datei <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> (der Service Worker). Sie werden sehen, dass die Listener für die Installation an <code>self</code> registriert sind. Dieses <code>self</code>-Schlüsselwort ist eine Möglichkeit, aus der Datei des Service Workers selbst auf den globalen Bereich des Service Workers 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 am Ereignisobjekt verfügbar ist, um zu signalisieren, dass der Browser die Installation des Service Workers nicht abschließen sollte, bis das darin enthaltene Versprechen 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 einem IndexedDB-Objekt-Store). 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 darstellt. Dann verwenden wir die Methode <a href=\"/de/docs/Web/API/Cache/addAll\"><code>Cache.addAll()</code></a>, um eine Reihe von Ressourcen abzurufen und deren Antworten im Cache 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>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 erledigt.</p>\n<h4 id=\"reaktion_auf_weitere_anfragen\">Reaktion auf weitere Anfragen</h4>\n<p>Mit dem Service Worker registriert und gegen unsere HTML-Seite installiert sowie den relevanten Ressourcen, die alle in unserem Cache hinzugefügt wurden, sind wir fast startklar. Es gibt noch eine Sache zu tun: Code schreiben, um auf weitere Netzwerkanfragen zu reagieren.</p>\n<p>Das ist es, was das zweite Stück Code in <code>sw.js</code> tut. Wir fügen einen weiteren Listener zum Service Worker globalen Bereich hinzu, der den Handler aufruft, wenn das <code>fetch</code>-Ereignis ausgelöst wird. Dies geschieht immer dann, wenn der Browser eine Anfrage für eine Ressource in dem Verzeichnis stellt, gegen das der Service Worker registriert ist.</p>\n<p>Innerhalb des Handlers protokollieren wir zunächst die URL der angeforderten Ressource. Wir liefern dann eine benutzerdefinierte Antwort auf die Anfrage, indem wir die Methode <a href=\"/de/docs/Web/API/FetchEvent/respondWith\"><code>FetchEvent.respondWith()</code></a> verwenden.</p>\n<p>Innerhalb dieses Blocks verwenden wir <a href=\"/de/docs/Web/API/CacheStorage/match\"><code>CacheStorage.match()</code></a>, um zu überprüfen, ob eine passende Anfrage (d. h. entspricht der URL) in einem beliebigen Cache gefunden werden kann. Dieses Versprechen erfüllt sich mit der passenden Antwort, wenn ein Match gefunden wird, oder <code>undefined</code>, wenn nicht.</p>\n<p>Wenn ein Match gefunden wird, geben wir es als benutzerdefinierte Antwort zurück. Wenn nicht, holen wir die Antwort 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>\n Und das war es für unseren Service Worker.\n Es gibt eine ganze Menge mehr, was Sie damit tun können – für weit mehr Details schauen Sie sich das <a href=\"https://github.com/mdn/serviceworker-cookbook\" class=\"external\" target=\"_blank\">Service Worker Kochbuch</a> an.\n 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.\n</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 der Fall ist, können Sie:</p>\n<ul>\n <li>Versuchen Sie, Ihr Netzwerk zu trennen / Ihr WLAN auszuschalten.</li>\n <li>Wählen Sie <em>Datei > Offline arbeiten</em> aus, wenn Sie Firefox verwenden.</li>\n <li>Gehen Sie zu den Entwickler-Tools, wählen Sie dann <em>Anwendung > Service Worker</em>, und aktivieren Sie das Kontrollkästchen <em>Offline</em>, wenn Sie Chrome verwenden.</li>\n</ul>\n<p>Wenn Sie Ihre Beispiel-Seite erneut aktualisieren, sollten Sie sehen, dass sie einwandfrei geladen wird. Alles wird offline gespeichert – die Seitenressourcen 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 jetzt. Wir hoffen, Sie fanden unseren Überblick über client-seitige Speichertechnologien nützlich.</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><ul class=\"prev-next\">\n <li><a class=\"button secondary\" href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs\"><span class=\"button-wrap\"> Zurück </span></a></li>\n <li><a class=\"button secondary\" href=\"/de/docs/Learn/JavaScript/Client-side_web_APIs\"><span class=\"button-wrap\"> Übersicht: Client-Side-Web-APIs</span></a></li>\n \n</ul>"}}],"toc":[{"text":"Client-seitige Speicherung?","id":"client-seitige_speicherung"},{"text":"Speicherung einfacher Daten — Web Storage","id":"speicherung_einfacher_daten_—_web_storage"},{"text":"Speicherung komplexer Daten — IndexedDB","id":"speicherung_komplexer_daten_—_indexeddb"},{"text":"Offline-Speicherung von Ressourcen","id":"offline-speicherung_von_ressourcen"},{"text":"Zusammenfassung","id":"zusammenfassung"},{"text":"Siehe auch","id":"siehe_auch"}],"summary":"Moderne Webbrowser unterstützen verschiedene Methoden, um Daten auf dem Computer des Benutzers zu speichern – mit Zustimmung des Benutzers – und diese bei Bedarf wieder abzurufen. Dies ermöglicht es Ihnen, Daten für die langfristige Speicherung zu behalten, Websites oder Dokumente für die Offline-Nutzung zu speichern, benutzerspezifische Einstellungen für Ihre Website beizubehalten und vieles mehr. Dieser Artikel erklärt die grundlegenden Funktionsweisen dieser Methoden.","popularity":0,"modified":null,"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":"中文 (简体)"}],"pageType":"unknown","source":{"folder":"de/learn/javascript/client-side_web_apis/client-side_storage","github_url":"https://github.com/mdn/translated-content/blob/main/files/de/learn/javascript/client-side_web_apis/client-side_storage/index.md","last_commit_url":"https://github.com/mdn/translated-content/commit/null","filename":"index.md"},"short_title":"Client-side storage","parents":[{"uri":"/de/docs/Learn","title":"Webentwicklung lernen"},{"uri":"/de/docs/Learn/JavaScript","title":"JavaScript — Dynamisches clientseitiges Scripting"},{"uri":"/de/docs/Learn/JavaScript/Client-side_web_APIs","title":"Client-Side-Web-APIs"},{"uri":"/de/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage","title":"Client-side storage"}],"pageTitle":"Client-side storage - Webentwicklung lernen | MDN","noIndexing":false}}</script></body></html>