渐进式web应用程序

by Ankita Masand

通过Ankita Masand

为什么渐进式Web应用程序很棒,以及如何构建一个 (Why Progressive Web Apps are great and how to build one)

In this tutorial, we’re going to build up the fundamentals of Progressive Web Applications (PWAs). I’ll help you understand the pain points of the traditional web and the need for something better to combat native applications. We’ll dive deeper into the components that make up a PWA — Service Workers, IndexedDB, manifest.json & Web Push Notifications. And the most interesting bit — we’ll build a PWA from scratch.

在本教程中,我们将建立渐进式Web应用程序(PWA)的基础。 我将帮助您了解传统网络的痛点,以及对更好地抵抗本机应用程序的需求。 我们将更深入地研究构成PWA的组件-Service WorkersIndexedDBmanifest.jsonWeb Push Notifications 。 最有趣的一点是-我们将从头开始构建PWA。

我如何想到编写本教程的想法 (How I Got the Idea to Write This Tutorial)

I was having dinner with my entire family, and a notification for a new text message popped up on my mobile phone. The message confirmed that I received a new paycheck. While this is regular news, my family gets delighted every time this happens.

我和全家人共进晚餐,手机上弹出一条新短信通知。 该消息确认我收到了新的薪水。 虽然这是正常新闻,但每次发生这种情况,我的家人都会感到高兴。

Taking advantage of the pleasant environment, my brother exclaimed that he wants a new mobile phone. When I asked him why did he need one, he said that his phone has become very slow and gets low memory warnings every now and then. I was surprised to hear this as his phone is more advanced than mine which is still working perfectly fine.

弟弟趁着宜人的环境大声疾呼,他想要一部新手机。 当我问他为什么需要一个电话时,他说他的电话变得非常缓慢,并时不时收到内存不足的警告。 听到这个消息,我感到很惊讶,因为他的电话比我的电话还先进,它仍然可以正常工作。

To satisfy my curiosity, I checked his phone and found that he has installed more than 40 applications for his diverse needs. ?‍♀️ There were two applications for reading blogs on different categories, two of them were for getting news updates, three of them were E-Commerce apps, three for gaming, one for keeping an eye on his mutual funds and another one for handling his bank account transactions and there were a few more that he didn’t use frequently.

为了满足我的好奇心,我检查了他的电话,发现他已经安装了40多种应用程序以满足他的各种需求。 ?有两个应用程序用于阅读不同类别的博客,其中两个用于获取新闻更新,其中三个是电子商务应用程序,三个用于游戏,一个用于监视他的共同基金,另一个用于处理他的银行帐户交易,还有一些他不经常使用的交易。

I asked him if he has ever tried going to the respective website before taking a bold step of installing the native application. He kept aside his piece of pizza and turned towards me in a mood of having a detailed conversation.

我问他在尝试大胆地安装本机应用程序之前,他是否曾尝试过访问各自的网站。 他把比萨饼放在一边,转过身来,想和我进行详细的交谈。

He began by saying that he has always visited a website first and it’s the website that forces him to download the native application by showing fat install banners. He says the experience on the web is so frustrating that it is impossible to get through even a simple task.

首先,他说自己总是首先访问一个网站,而该网站迫使他通过显示胖安装横幅来下载本机应用程序。 他说,网上的体验令人沮丧,以至于即使完成一个简单的任务也无法完成。

His E-Commerce applications are really great at giving him timely updates on his orders and do an amazing job of informing him of discounts by sending push-notifications. The user experience on native applications is simply amazing and the web can’t beat that. He was stern in his opinion about the web. However, he agreed that the size of the native application bloats his phone memory but he cannot do anything in that regard.

他的电子商务应用程序确实非常擅长于及时向他发送订单更新,并通过发送推送通知来向他告知折扣信息。 在本机应用程序上的用户体验简直令人赞叹, 网络无法比拟。 他对网络的看法很严厉。 但是,他同意本机应用程序的大小使他的手机内存膨胀,但是他在这方面无能为力。

人们对网络的误解 (Misconceptions People Have About the Web)

My brother thinks exactly what most users think about the web. The traditional web is slow and ugly. Let’s take a moment and check out Twitter on the mobile web, popularly called Twitter Lite, and understand the significance of the word traditional in my last statement.

我的兄弟完全想到了大多数用户对网络的看法。 传统的网络缓慢且难看。 让我们花点时间在移动网络上查看Twitter (通常称为Twitter Lite),并在我上一次声明中了解传统一词的含义。

Is the experience on par with the native app? It loads instantly. There is no janky scrolling. It doesn’t look like an old traditional website. You might’ve noticed a small banner at the bottom asking you to Add Twitter to your home screen. Is it the fancier way of urging users to install native applications? No, it isn’t. It won’t download a native application of megabytes in size. It is asking you to add Twitter Lite on your home screen. It literally means adding a shortcut to access twitter mobile web using that icon on the home screen.

体验与本地应用程序相提并论吗? 它立即加载。 没有混乱的滚动。 它看起来不像是一个古老的传统网站 。 您可能已经注意到底部有一个小横幅,要求您将Twitter添加到主屏幕。 是敦促用户安装本机应用程序的更好方法吗? 不,不是。 它不会下载兆字节大小的本机应用程序。 它要求您在主屏幕上添加Twitter Lite。 从字面上看,这意味着使用主屏幕上的该图标添加访问Twitter移动Web的快捷方式。

Let’s experiment with this by clicking on Add Twitter to home screen and check out what the newer web has to offer. In case the banner didn’t appear in your case, please click on the three dots on the right side and choose option Add to home screen. Now, click on the twitter icon from your home screen. Isn’t that amazing? Oh yes, this app can also send you real-time push notifications. The web won’t feel like a lost world now. Once you opt-in for push notifications on a web application, it does a great job of engaging users by showing them all the updates.

让我们通过单击“ 将Twitter添加到主屏幕”并查看较新的Web提供的内容来进行试验。 如果横幅没有出现在您的情况下,请单击右侧的三个点,然后选择选项添加到主屏幕 。 现在,在主屏幕上单击Twitter图标。 那不是很神奇吗? 哦,是的,该应用程序还可以向您发送实时推送通知。 网络现在不会像失去的世界。 在Web应用程序上选择接受推送通知后,通过向用户显示所有更新,可以很好地吸引用户。

There is one more important thing that is lacking in traditional old web — the ability to deal with intermittent or no internet connection. The Web behaves quite differently on 2G devices compared to on WIFI. Most of the times, it’s nothing or a loader on the screen while browsing on a 2G connection. This is frustrating to the end user.

传统的旧网络还缺少另一项重要的功能-处理间歇性或无互联网连接的能力。 与WIFI相比,Web在2G设备上的行为完全不同。 在大多数情况下,在2G连接上浏览时,什么都没有,或者屏幕上没有加载程序。 这使最终用户感到沮丧。

The good news is, the modern web can deal with this problem too. You don’t see the dinosaur when your internet goes off. It’s a nice application shell that pops up when you are not connected to the internet. I really like the way Trivago deals with this problem, they show a nice application shell to play around an offline maze.

好消息是,现代网络也可以处理此问题。 互联网中断时,您看不到恐龙。 这是一个不错的应用程序外壳,当您未连接到Internet时会弹出。 我非常喜欢Trivago处理此问题的方式,它们展示了一个不错的应用程序外壳,可以在离线迷宫中播放。

Let’s check out one more application of this kind — Financial Times. Load Financial Times in your browser and now switch off your internet. Reload the page. The experience is still the same. Isn’t this something that makes the web look great? These web applications that solve the pain points of the traditional web are popularly called Progressive Web Applications.

让我们看看另一种这种应用程序- 金融时报 。 在浏览器中加载《 金融时报》 ,现在关闭互联网。 重新加载页面。 经验还是一样。 这不是使网络看起来很棒的东西吗? 这些解决传统Web难题的Web应用程序通常称为渐进Web应用程序

In this tutorial, we’re going to explore Progressive Web Applications and also build one from scratch.

在本教程中,我们将探索渐进式Web应用程序,并从头开始构建一个。

渐进式Web应用程序的好处 (Benefits of Progressive Web Applications)

Progressive Web Applications (PWAs) are:

渐进式Web应用程序(PWA)是:

快速 (Fast)

They make good use of local caches to store static assets. Caching of static assets reduces the number of rides to the server to fetch these assets on every load. This makes for an incredible user experience similar to that of native applications. They respond quickly to user interactions.

它们充分利用了本地缓存来存储静态资产。 缓存静态资产减少了在每次负载时获取这些资产的服务器运行次数。 这提供了与本机应用程序相似的令人难以置信的用户体验。 他们快速响应用户交互。

可靠 (Reliable)

PWAs load data almost instantly. Every fetch network request from the application goes through Service Workers (more on that later). They operate the cache (IndexedDB or any other local cache). Service Workers can send the response to a network request directly from the cache in case of intermittent or slow internet connections. PWAs work reliably even on 2G connections.

PWA几乎立即加载数据。 来自应用程序的每个获取网络请求都将通过Service Workers(稍后会进行详细介绍)。 他们操作缓存(IndexedDB或任何其他本地缓存)。 如果Internet连接是间歇性的或速度较慢,服务人员可以直接从缓存中发送对网络请求的响应。 即使在2G连接上,PWA也可以可靠地工作。

参与 (Engaging)

Native applications leverage the power of operating systems to show important notifications to the users and this is one of the powerful features of an application. Sending timely push notifications helps to retain users for a longer duration. PWAs make use of web push notifications to inform users of relevant updates.

本机应用程序利用操作系统的功能向用户显示重要通知,这是应用程序的强大功能之一。 及时发送推送通知有助于将用户保留更长的时间。 PWA利用Web推送通知来通知用户相关的更新。

Progressive Web Applications is used as terminology for web applications that are fast, reliable and engaging and they provide an experience similar to that of native applications. Applications that are eligible to be called Progressive Web Applications consists of and employ the following:

渐进式Web应用程序用作快速,可靠和引人入胜的Web应用程序的术语,它们提供的体验类似于本机应用程序。 有资格被称为渐进式Web应用程序的应用程序由以下各项组成并采用:

Service Workers

服务人员

Service Workers, in simple terms, are a few lines of JavaScript code that keep running in the background. However, they go to a dormant state when they are not in use. They operate as an event-driven system. Whenever a particular event (for example, a fetch request to the server) is invoked, service workers come to life.

简而言之, 服务工作者是几行JavaScript代码,它们始终在后台运行。 但是,它们在不使用时会进入Hibernate状态。 它们作为事件驱动系统运行。 每当调用特定事件(例如,对服务器的提取请求)时,服务工作人员就会活跃起来。

We can handle the response of the fetch event using the fetch event listener in the Service Worker. For a service worker to start doing its work of handling fetch requests and a few other events, it should be registered, installed and activated on a web application.

我们可以使用Service Worker中的fetch事件侦听器来处理fetch事件的response 。 为了使服务工作者开始处理获取请求和其他一些事件,应该在Web应用程序上对其进行注册,安装和激活。

IndexedDB or any other local cache

IndexedDB或任何其他本地缓存

PWAs store the static assets like JavaScript files, stylesheets, and images in the local cache for subsequent visits. Some of the PWAs make use of IndexedDB, which is basically a structured key-value pair data structure. IndexedDB is used for storing large amounts of data as compared to other client-side storage options.

PWA将静态资源(如JavaScript文件,样式表和图像)存储在本地缓存中,以供后续访问。 一些PWA使用IndexedDB,它基本上是结构化的键/值对数据结构。 与其他客户端存储选项相比,IndexedDB用于存储大量数据。

We saw earlier the way Financial Times handles the no internet condition. It still displays all the articles on the home page. It makes use of IndexedDB to store data from these articles.

我们之前已经看过《 金融时报》处理无互联网状况的方式 。 它仍然在主页上显示所有文章。 它利用IndexedDB来存储这些文章中的数据。

Let’s see this in action. You’ll find IndexedDB in the Chrome DevTools under Applications tab. Under IndexedDB, go to the Articles section.

让我们来看看实际情况。 您可以在Chrome DevTools的“应用程序”标签下找到IndexedDB。 在IndexedDB下,转到“ 文章”部分。

Web Push Notifications

网络推送通知

Service Workers also listen to a push event and have a respective push event handler that takes care of showing the push notification to the user. An application must have the user’s permission in order to show them push notifications. Once a user opts-in for receiving push notifications, the browser generates a unique token for them. The server can then communicate with the user using this unique token.

服务人员还监听推送事件,并有一个各自的推送事件处理程序,负责将推送通知显示给用户。 应用程序必须具有用户的权限才能向他们显示推送通知。 一旦用户选择接收推送通知,浏览器就会为他们生成一个唯一的令牌。 然后,服务器可以使用此唯一令牌与用户通信。

manifest.json File

manifest.json文件

manifest.json is typically a metadata file of an application. An application includes the manifest.json in index.html as follows

manifest.json通常是应用程序的元数据文件。 应用程序在index.html中包含manifest.json,如下所示

<link rel="manifest" href="manifest.json">

<link rel="manifest" href="manifest.jso n”>

manifest.json does the job of telling the browser that the application is a PWA. It tells the browser the Name, Background Color, Theme Color, and Icons to be used for this application. It also tells the mode in which the application should be opened. For example, a standalone mode launches a PWA by giving a feel similar to that of a native application.

manifest.json的作用是告诉浏览器该应用程序是PWA。 它告诉浏览器该应用程序要使用的名称,背景色,主题色和图标。 它还指示应打开应用程序的模式。 例如, 独立模式通过提供与本机应用程序相似的感觉来启动PWA。

Rich User Experience

丰富的用户体验

PWAs are known to have a rich user experience. They access the static assets directly from the cache so there is no delay in responding to user interactions.

众所周知,PWA具有丰富的用户体验。 他们直接从缓存访问静态资产,因此响应用户交互没有延迟。

Let’s build a Progressive Web Application by making use of the components listed above.

让我们通过使用上面列出的组件来构建一个渐进式Web应用程序。

用例—建立书籍宝库 (Use Case — Building a Treasure Trove of Books)

We will be building an application called BooksKeep. It will help in maintaining a systematic record of the books we’ve read and also the ones that are in our pipeline. No wise word learned should go in vain.

我们将构建一个名为BooksKeep的应用程序。 这将有助于维护我们已阅读的书籍以及我们正在准备中的书籍的系统记录。 学到的明智的话是徒劳的

The following features will be incorporated in this application:

以下功能将并入此应用程序:

  1. Displaying a list of books (Title, Author, Summary, & Favorite Quotes)显示书籍清单(标题,作者,摘要和最爱报价)
  2. Adding a new book to the list将新书添加到列表中

先决条件—我们的技术栈 (Prerequisites — Our Technology Stack)

  • React — for building the front-end

    React —用于构建前端

  • IndexedDB — for storing the books records (please note, there is no back-end database)

    IndexedDB-用于存储图书记录(请注意,没有后端数据库)

  • WebPack — as a development server and for bundling assets

    WebPack —作为开发服务器和捆绑资产

Let get going! To make things simple, I’ve created a boilerplate to get started with.

开始吧! 为简单起见 ,我创建了一个样板开始。

了解样板 (Understanding the Boilerplate)

package.json - package.json contains the project dependencies. When you do npm install, these dependencies will be downloaded in your system. Since we're using React to build up our front-end, react & react-dom libraries are included in the dependencies section.

package.json - package.json包含项目依赖项。 当您执行npm install ,这些依赖项将下载到您的系统中。 由于我们使用React构建前端,因此reactreact-dom库包含在dependencies部分中。

In devDependencies object, babel presets and few webpack related plugins are included. Babel is a JavaScript compiler that is used for syntax transformation, converting the next-gen JavaScript into a browser compatible version.

devDependencies对象中,包含babel预设和一些与Webpack相关的插件。 Babel是用于语法转换JavaScript编译器,可将下一代JavaScript转换为与浏览器兼容的版本。

The browser doesn't understand the React syntax directly, so we're using babel-preset-react to convert React and JSX into JavaScript that the browser understands. We're using WebPack as a module bundler.

浏览器无法直接理解React语法,因此我们正在使用babel-preset-react将React和JSX转换为浏览器可以理解JavaScript。 我们使用WebPack作为模块捆绑器。

webpack.config.js contains the configuration setup required for generating a bundle of static assets. The entry object in module.exports contains the entry point of the application, which in our case is app.js. Webpack generates a dependency graph using this entry point and keeps adding dependencies in the bundle starting from app.js. The output object contains the path of the output folder and filename generates dynamic filenames based on their value in the entry object. In our case, it will be bundle.js as we've mentioned bundle in the entry point.

webpack.config.js包含生成静态资产捆绑包所需的配置设置。 module.exports中的entry对象包含应用程序的入口点,在本例中为app.js Webpack使用此入口点生成依赖关系图,并从app.js开始不断在捆绑包中添加依赖关系。 的output对象包含输出文件夹的路径和filename ,生成基于它们在该条目对象的值的动态文件名。 在我们的例子中,它将是bundle.js就像我们在入口点提到的bundle一样。

Next, there are some rules to convert .js & .scss specific files. These files are to be transformed with their respective loaders before adding them to the main bundle.

接下来,有一些规则可以转换.js和.scss特定文件。 在将这些文件添加到主捆绑包之前,将使用它们各自的加载程序对其进行转换。

  • HTMLWebpackPlugin adds the generated output bundles in the provided index.html template.

    HTMLWebpackPlugin将所生成的输出包添加到提供的index.html模板中。

  • ExtractTextPlugin moves the .css modules into a separate file.

    ExtractTextPlugin将.css模块移动到单独的文件中。

  • CopyWebpackPlugin simply copies the manifest.json file and service-worker.js file from src to dist.

    CopyWebpackPlugin只是将manifest.json文件和service-worker.js文件从src复制到dist

We will be building up src along this tutorial. For now, it contains index.html that has one div element with id app. app.js is the root component of the application. It contains simple header & body components for now.

我们将在本教程中构建src 。 现在,它包含index.html ,其中有一个div元素,其ID为appapp.js是应用程序的根组件。 现在,它包含简单的标题和正文组件。

Let’s start building our BooksKeep PWA. We will be building this progressively in the following steps:

让我们开始构建我们的BooksKeep PWA 。 我们将通过以下步骤逐步构建此功能:

  1. Building a table component for displaying book records构建用于显示账簿记录的表格组件
  2. Provision to add a new book in the table规定在表中添加新书
  3. Storing book records in IndexedDB在IndexedDB中存储帐簿记录
  4. Adding Service Worker to cache static assets添加Service Worker以缓存静态资产
  5. Adding manifest.json添加manifest.json

构建用于显示账簿记录的表组件 (Building a Table Component for Displaying Book Records)

We’re using react-bootstrap for building the UI. Let's import the Table component from react-bootstrap.

我们正在使用react-bootstrap来构建UI。 让我们从react-bootstrap导入Table组件。

Start the server by using the command npm start in your terminal. Head over to localhost:8080/dist/. We don't have any book records yet so the table is empty. BooksHeaders are being imported from the constants folder. Please add BooksHeaders in books-headers.js file in the constants folder from here.

通过在终端中使用命令npm start服务器。 转到localhost:8080/dist/ 。 我们还没有任何书籍记录,因此该表为空。 从常量文件夹导入BooksHeaders 。 请从此处开始 ,在constants文件夹中的books-headers.js文件中添加BooksHeaders

BooksHeaders is simply an array of objects that we're displaying in the table. getTableMarkup function builds up the table headers with getTableHeaders & body with getTableData functions. booksData maintains the state of the component. If any new book record is to be added, it should be pushed into booksData array.

BooksHeaders只是我们在表中显示的对象数组。 getTableMarkup功能建立起与表头getTableHeaders &体getTableData功能。 booksData维护组件的状态。 如果要添加任何新书记录,则应将其推入booksData数组。

规定在表中添加新书 (Provision to Add a New Book in the Table)

Let’s take it further and add our first book record in the table. All we have to add is to import the BookForm component from the base folder and provide it a onSubmit prop. onSubmit prop accepts a function that will be called when the user clicks on the submit button in the form, and that will give us the details of the new book. Once you're done with that, your Body Component should look like this.

让我们更进一步,在表中添加我们的第一本书记录。 我们需要添加的BookForm从基本文件夹导入BookForm组件,并为其提供onSubmit道具。 onSubmit prop接受一个函数,当用户单击表单中的“提交”按钮时,该函数将被调用,这将为我们提供新书的详细信息。 完成此操作后,您的“身体组件”应该看起来像这样 。

Here’s the BookForm component:

这是BookForm组件:

FieldGroup is just a wrapper for labeled inputs. Please put this inside the field-group.js file in the utils folder. BookForm component maintains its state in the formData object. Whenever a user enters name, author or summary, it gets saved in the component state. The submit button passes the component state to the parent Body component, which then adds it to its state - booksData array.

FieldGroup只是带有标签的输入的包装。 请把这个内field-group.js在文件utils文件夹。 BookForm组件在formData对象中维护其状态。 每当用户输入名称,作者或摘要时,它都会保存在组件状态中。 提交按钮将组件状态传递给父Body组件,然后将其添加到其状态booksData数组。

After adding a book record, you'll see that your table is now populated with that record. But when you refresh the page, all of this is gone. We've got to fix this.

添加帐簿记录后,您会看到表格中已经填充了该记录。 但是,刷新页面后,所有这些都消失了。 我们必须解决此问题。

在IndexedDB中存储书籍记录 (Storing Book Records in IndexedDB)

IndexedDB is a structured client-side storage database. The records in IndexedDB are stored as key-value pairs. We’ll be saving the book records in IndexedDB. IndexedDB provides APIs for adding, deleting and updating the records in a database. Let’s explore these APIs by creating a wrapper in the indexeddb.js file in the utils folder.

IndexedDB是结构化的客户端存储数据库。 IndexedDB中的记录存储为键值对。 我们将图书记录保存在IndexedDB中。 IndexedDB提供用于在数据库中添加,删除和更新记录的API。 让我们通过在utils文件夹中的indexeddb.js文件中创建一个包装器来探索这些API。

Operations performed on IndexedDB are asynchronous in nature. So, the IndexedDB APIs provide appropriate hooks for success and error events.

本质上,在IndexedDB上执行的操作是异步的。 因此,IndexedDB API为成功和错误事件提供了适当的挂钩。

First, we’ll have to create our database. Let’s write a initialize function that will handle the initialization tasks:

首先,我们必须创建我们的数据库。 让我们编写一个initialize函数来处理初始化任务:

In the above code snippet, BooksKeep is the name of the IndexedDB database and books is an ObjectStore. ObjectStore is analogous to a table in SQL. The statement idb.open(DB, 1) is an asynchronous request to open IndexedDB database BooksKeep, and the second parameter 1 signifies the version of the database. The request variable is of type IDBOpenDBRequest.

在上面的代码片段中, BooksKeep是IndexedDB数据库的名称, booksObjectStoreObjectStore类似于SQL中的表。 语句idb.open(DB, 1)是打开IndexedDB数据库BooksKeep的异步请求,第二个参数1表示数据库的版本。 请求变量的类型为IDBOpenDBRequest

We've defined onsuccess, onerror and onupgradeneeded functions on the request object to be called at the respective events. For example, onsuccess callback would be called when the database is opened successfully and in onsuccess method, we're caching the instance of the BooksKeep database. onupgradeneeded method is invoked whenever there is a change in the version of the database.

我们已经在请求对象上定义了onsuccessonerroronupgradeneeded函数,以在相应事件中调用。 例如,成功打开数据库时将调用onsuccess回调,而在onsuccess方法中,我们正在缓存BooksKeep数据库的实例。 每当数据库版本发生更改时,都会调用onupgradeneeded方法。

Currently, with version 1, we've added only one ObjectStore called as books. Let's say, at a later stage, when our application grows we decide to add one more ObjectStore. We'll have to upgrade the version of our database to 2 and add the schema of this new ObjectStore in onupgradeneeded method.

当前,在第1版中,我们仅添加了一个称为books ObjectStore。 假设在以后的阶段,当我们的应用程序增长时,我们决定再添加一个ObjectStore。 我们必须将数据库版本升级到2,并在onupgradeneeded方法中添加此新ObjectStore的架构。

We will be writing three important methods — get, update & delete — in our IndexedDB wrapper. The general idea for performing any of these operations is to first get the instance of the store, wrap the operation in a transaction, and then write success and error event handlers for the respective asynchronous requests. A transaction is simply a wrapper around an operation to ensure data integrity. If any of the actions in a transaction fails, then no action is performed on the database.

我们将编写三个重要方法- 获取更新删除-在我们的IndexedDB的包装。 执行这些操作中任何一个的总体思路是,首先获取存储实例,将操作包装在事务中,然后为相应的异步请求编写成功和错误事件处理程序。 事务只是用于确保数据完整性的操作的包装。 如果事务中的任何操作失败,则不会对数据库执行任何操作。

For example, our put or update method will look something like this:

例如,我们的put或update方法将如下所示:

update method takes three parameters:

update方法采用三个参数:

type is the name of the objectStore, data is the book record that we intend to add/update in our objectStore, and callback is of type function that would be called after successfully adding data in the objectStore.

type是objectStore的名称, data是我们打算在objectStore中添加/更新的书籍记录,而callback是type函数的类型,该函数将在objectStore中成功添加data之后被调用。

transaction is defined on the IDBOpenDBRequest instance and it takes the name of the objectStore and the mode with which the operation is to be performed. In this case, the mode is readwrite since we're writing to the objectStore.

transactionIDBOpenDBRequest实例上定义,并采用IDBOpenDBRequest的名称和执行操作的方式。 在这种情况下,该模式是readwrite因为我们正在写入objectStore。

As mentioned previously, IndexedDB accepts data in the form of key-value pairs. We're using timestamp to generate a unique identifier for a particular record. store.put(data) asynchronously adds book records into the books objectStore. On the same lines, I've added get & delete methods in our wrapper. Please check the complete code of IndexedDB wrapper here.

如前所述,IndexedDB接受键值对形式的数据。 我们正在使用时间戳生成特定记录的唯一标识符。 store.put(data)异步将书籍记录添加到books objectStore中。 同样,我在包装器中添加了get&delete方法。 请在此处检查IndexedDB包装器的完整代码。

Now that our IndexedDB wrapper is all set, it’s time to use the add/update function from our wrapper whenever a user tries to add a new book record. Let’s modify our Body Component to accommodate these changes.

现在,我们的IndexedDB包装器已经全部设置好了,每当用户尝试添加新的书记录时,就该使用来自包装器的添加/更新功能了。 让我们修改我们的身体组件以适应这些变化。

First import IndexedDbWrapper in the Body component. We will be calling the initialize function of IndexedDbWrapper in componentDidMount. The initialize method takes the callback as initializeDB function, which is defined in the Body Component. initializeDB does the work of setting up the initial state of our application by fetching the stored books records from IndexedDB.

首先在Body组件中导入IndexedDbWrapper 。 我们将在componentDidMount调用IndexedDbWrapperinitialize函数。 initialize方法将回调作为在主体组件中定义的initializeDB函数。 initializeDB通过从IndexedDB获取存储的图书记录来完成设置应用程序初始状态的工作。

One last thing to do with IndexedDbWrapper is to call its update method on submission of a book record. We've to modify the onSubmit method of the Body component as follows:

IndexedDbWrapper最后一件事是在提交书记录时调用其update方法。 我们必须修改Body组件的onSubmit方法,如下所示:

Now, the new record will be first added to IndexedDB, and once that is done successfully, we’re updating the state of the component. Try adding a new book record and reloading the page. You will still see your book record in the table. Here’s where it is coming from!

现在,新记录将首先添加到IndexedDB,一旦成功完成,我们将更新组件的状态。 尝试添加新的书记录并重新加载页面。 您仍然会在表格中看到您的图书记录。 这就是它的来历!

Let’s add one record and refresh the page. Data is preserved and that’s exactly what we wanted. We’ve built up a means to fetch data directly on the client-side. We’re getting closer to our goal of building a Progressive Web Application.

让我们添加一条记录并刷新页面。 数据被保留,这正是我们想要的。 我们已经建立了一种直接在客户端获取数据的方法。 我们正在接近构建渐进式Web应用程序的目标。

添加服务工作者以缓存静态资产 (Adding Service Worker to Cache Static Assets)

The next step is to leverage the power of Service Workers by fetching static assets from the cache. A service worker first has to be registered on a web page.

下一步是通过从缓存中获取静态资产来利用Service Worker的功能。 首先必须在网页上注册服务人员。

Service Worker Registration

服务人员注册

initializeSW function is defined in the Body component, and we'll call it in componentDidMount lifecycle hook. serviceWorker is defined on navigator. According to MDN,

initializeSW函数在Body组件中定义,我们将在componentDidMount生命周期挂钩中对其进行调用。 serviceWorker是在navigator上定义的。 根据MDN,

the Navigator interface represents the state and the identity of the user agent. It allows scripts to query it and to register themselves to carry on some activities.

Navigator界面表示用户代理的状态和身份。 它允许脚本查询并注册自己以进行一些活动。

A Service Worker is registered using the register method defined on navigator.serviceWorker object. The register method takes the URL of the service worker file. It returns a Promise which resolves when the service worker is registered successfully on the webpage. Once this is done, you'll see a success message in the console. By default, service workers can intercept all the fetch requests coming from the web page.

使用在navigator.serviceWorker对象上定义的register方法注册Service Worker。 register方法采用服务工作者文件的URL。 它返回一个Promise ,用于解决服务工作者在网页上成功注册的时间。 完成此操作后,您将在控制台中看到成功消息。 默认情况下,服务人员可以拦截来自网页的所有提取请求。

register method also takes an optional second parameter, which defines the scope of the service worker.

register方法还带有一个可选的第二个参数,该参数定义了服务工作者的scope

navigator.serviceWorker.register('./service-worker.js', { scope: '/products' })

The above service worker will intercept only /products/* requests. So, something like /payments is not intercepted by the above service worker.

上述服务人员将仅拦截/products/*请求。 因此,上述服务工作者不会拦截诸如/payments类的东西。

As said earlier, Service Workers operate as an event-driven system. After successful registration, an install event is triggered. We can make use of the install event handler for initialization tasks. In our case, we will be setting up our cache for storing static assets.

如前所述,服务工作者是作为事件驱动的系统运行的。 成功注册后,将触发install事件。 我们可以将install事件处理程序用于初始化任务。 在我们的情况下,我们将设置缓存以存储静态资产。

Here’s the install event handler:

这是安装事件处理程序:

event.waitUntil makes sure that the service worker is active while the URLS are getting added into the cache.

event.waitUntil确保在将URL添加到缓存中时,服务工作器处于活动状态。

The service worker hasn’t yet started doing its magic. After getting installed successfully, an activate event is triggered and this is a good place to clear off old unused caches. Let's do our bit:

服务人员尚未开始发挥作用。 成功安装后,将activate事件,这是清除旧的未使用缓存的好地方。 让我们尽力而为:

activate event handler takes care of deleting all the caches except bookskeep-cache. When a web page makes a network request to the server, the fetch event of the service worker is triggered. So, if we were to manipulate or modify the response to be sent for a particular request, we'll have to do this in the fetch event handler.

activate事件处理程序负责删除除bookskeep-cache之外的所有bookskeep-cache 。 当网页向服务器发出网络请求时,将触发服务工作者的获取事件。 因此,如果我们要操纵或修改要针对特定​​请求发送的响应,则必须在fetch事件处理程序中执行此操作。

event.respondWith method lets us send a modified response back to the client. It returns a Promise that resolves to a valid response. cache.match checks if the request is a valid resource for caching (if you remember, we've added a few specific URLs to urlsToCache variable in the install event handler).

event.respondWith方法使我们可以将修改后的响应发送回客户端。 它返回一个可解决有效响应的Promise。 cache.match检查请求是否是用于缓存的有效资源(如果您还记得的话,我们在安装事件处理程序中为urlsToCache变量添加了一些特定的URL)。

If the response to that request is present in the cache, we send it directly to the client otherwise, we request that resource from the server, put it into the cache for subsequent hits, and send it to the client.

如果对该请求的响应存在于高速缓存中,则将其直接发送到客户端,否则,我们从服务器请求该资源,将其放入高速缓存中以供后续命中,然后将其发送给客户端。

Here’s the service worker file with the three event handlers explained above.

这是带有上面介绍的三个事件处理程序的服务工作者文件。

添加manifest.json (Adding manifest.json)

short_name is used on the home screen as the name of the application. In case short_name is not provided, then the name property is used in its place. icons show up as a home screen icon for the application in the app launcher and on the splash screen. start_url tells the browser about the starting page of the app. A user will be directed to this URL when the app is launched. standalone as the display property of the app gives it the look & feel of a native application. The application runs in its own window and hides some of the browser specific elements like URL bar. background_color sets the color of the splash screen when the application is first launched and theme_color tells about the color of the toolbar.

short_name在主屏幕上用作应用程序的名称。 如果未提供short_name ,则将使用name属性。 icons在应用程序启动器和启动屏幕中显示为该应用程序的主屏幕图标。 start_url告诉浏览器应用程序的起始页面。 启动应用程序后,系统会将用户定向到该URL。 作为应用程序的显示属性standalone提供给它的本机应用程序外观。 该应用程序在其自己的窗口中运行,并隐藏某些浏览器特定的元素,例如URL栏。 background_color设置应用程序首次启动时的初始屏幕颜色, theme_color告知工具栏的颜色。

This is it. We’ve set up our BooksKeep PWA. Let’s have a quick recap of the things we learned in this tutorial:

就是这个。 我们已经设置了BooksKeep PWA 。 让我们快速回顾一下本教程中学到的知识:

  1. The traditional web lacks some of the important features that native applications provide out of the box. Progressive Web Applications help in improving the user experience on the web tremendously. They are fast, reliable, and engaging and provide an experience similar to that of native applications.传统的Web缺少本机应用程序提供的一些重要功能。 渐进式Web应用程序有助于极大地改善Web上的用户体验。 它们快速,可靠且引人入胜,并提供与本机应用程序相似的体验。
  2. PWAs make use of Service Workers, IndexedDB (or any other local cache), manifest.json, and Web Push Notifications.PWA使用服务工作者,IndexedDB(或任何其他本地缓存),manifest.json和Web推送通知。
  3. Service Workers operate as an event-driven system and listen for fetch & push events. fetch event lets us send the response to a network request directly from the cache in case of slow or intermittent connections. push event lets us show push-notifications to the user and helps in engaging user by apprising them of timely updates.

    服务工作者作为事件驱动系统运行,并监听提取和推送事件。 fetch事件使我们可以在连接缓慢或间歇性情况下直接从缓存将对网络请求的响应发送给网络请求。 push事件使我们可以向用户显示推送通知,并通过通知他们及时更新来帮助吸引用户。

  4. IndexedDB is a key-value structure. It helps in storing a massive amount of data on the client-side. manifest.json informs the browser about some of the important properties of an application.

    IndexedDB是键值结构。 它有助于在客户端存储大量数据。 manifest.json通知浏览器应用程序的一些重要属性。

  5. We learned how to get started building a Progressive Web Application.我们学习了如何开始构建渐进式Web应用程序。

This was a quick introduction to Progressive Web Applications. If you want to explore more, here are some of the resources:

这是渐进式Web应用程序的快速介绍。 如果您想探索更多,这里有一些资源:

  1. An Extensive Guide To Progressive Web Applications

    渐进式Web应用程序的广泛指南

  2. Check out my BooksKeep application on GitHub. I’ve added a few more features like updating book records, adding quotes & support for web push notifications. I’ll keep adding more!

    在GitHub上查看我的BooksKeep应用程序。 我添加了一些其他功能,例如更新账簿记录,添加报价和对Web推送通知的支持。 我会继续添加更多!

  3. Service Workers

    服务人员

Please let me know if you found this tutorial to be helpful and share it with whomever you think might benefit from it.

如果您觉得本教程对您有帮助,请告诉我,并与您认为可以从中受益的任何人分享。

Originally published at hashnode.com.

最初发布在hashnode.com上 。

翻译自: https://www.freecodecamp.org/news/benefits-of-progressive-web-applications-pwas-and-how-to-build-one-a763e6424717/

渐进式web应用程序

渐进式web应用程序_为什么渐进式Web应用程序很棒,以及如何构建一个相关推荐

  1. 渐进式web应用程序_通过渐进式Web应用程序吸引用户并增强他们的体验

    渐进式web应用程序 by Dave Gray 戴夫·格雷(Dave Gray) 通过渐进式Web应用程序吸引用户并增强他们的体验 (Engage your users and enhance the ...

  2. python 客户端应用程序_创建python Web服务和C#客户端应用程序的最佳方法 - c#

    我正在寻找一种简单可靠的方法来创建Python Web Service并从.Net(c#)应用程序中使用它. 我发现了很多不同的库,其中一个库比另一个库好,但是似乎没有人提供关于Python Web ...

  3. java web应用程序_说说Java Web中的Web应用程序|乐字节

    大家好,我是乐字节的小乐,今天接着上期文章<Javaweb的概念与C/S.B/S体系结构>继续往下介绍Java Web ,这次要说的是web应用程序. 1. Web 应用程序的工作原理 W ...

  4. web开发指南_成为专业Web开发人员的实用指南

    web开发指南 This article is meant to serve as a practical guide to becoming a professional web developer ...

  5. mysql web 报表工具_.net的web报表设计工具

    e表介绍 e表是一个功能强大的Web报表工具,提供了高效的报表设计方案.强大的Web报表展现能力.灵活的部署机制.使用e表可使复杂报表的设计简单化,以往难以实现的报表可以轻松实现,避免了大量的复杂SQ ...

  6. java web api 版本控制_怎么做 Web API 版本控制?

    简评:这是 fly.io分享的一篇文章,讲了他们是怎么对自家 REST API 做版本控制的.另外还有很多其他的技术文章,个人感觉还不错,感兴趣的同学可以看一看. API 设计是一个都快被说烂了的主题 ...

  7. web开发方法_确保进入Web开发的最快方法

    web开发方法 做很多项目. (Do lots of projects.) I'm not kidding, it's really that simple. If you've internaliz ...

  8. web全屏_当前的Web设计趋势:全屏全屏主页

    web全屏 全屏启动是当前网络上最常见的模式之一. 有些人喜欢它,有些人讨厌它,但是无论您有什么感觉,我们都可以看看一些值得注意的例子,并在讨论过程中谈论最佳实践. 关于设计融合的注意事项 术语&qu ...

  9. linux 易语言窗口程序_易语言开发Linux程序

    令人兴奋的是易语言可以开发Linux程序,易语言是一个跨平台的开发工具,支持Windows及Linux.使用易语言开发Linux程序,您可以在Windows环境下编写基本于Windows的程序,及编写 ...

最新文章

  1. 关于python赋值语句下列选项中描述正确的是_关于Python的分支结构,以下选项中描述正确的是()。...
  2. Robot Framework 自动化框架 - 定制自己的library
  3. python的垃圾回收机制和析构函数__del__
  4. oracle语句加减,oracle时间加减的语句写法
  5. 程序员数学基础【七、等比数列 棋盘麦粒】
  6. spring-data-mongodb查询结果返回指定字段
  7. 现代软件工程 作业 团队第一个作业
  8. 客户端如何连接oracle数据库,ORACLE的客户端如何连接到数据库(三)
  9. mysql设置空值显示null_mysql的空值与NULL的区别
  10. Kraken发言人:公司可能会考虑明年上市,但不适合SPAC模式
  11. ORACLE查询表最近更改数据的方法
  12. 安装8in1飞行模拟器过程
  13. SQL SERVER 2005 批量收缩数据库
  14. mysql确定数据表中是否存在某字段_MySQL判断表是否存在某个列
  15. 【常见手机操作系列】开启微信收款语音功能
  16. 如何释放计算机的ip地址,电脑执行释放DNS和更新IP的命令是什么?怎么执行
  17. 给新一代IT人的分享
  18. python爬虫天气实例_Python爬虫实例扒取2345天气预报
  19. Java的一些冷门知识点
  20. 02华为大数据HCIE_Data Mining 数学基础 测试一下

热门文章

  1. 前端开发练习——包含了计时功能的动画时钟
  2. VPX-M1 3U VPX 刀片计算机产品
  3. 实现简单的增删改查(Asp.Net MVC+Layui)
  4. 一个window下的简单的全局快捷键向指定的进程发送的c代码与exe程序下载(二)
  5. 关于android的广告词,关于android:随心译无广告的专属实时翻译神器
  6. ML-Agents案例之地牢逃脱
  7. 中国经济坐标里,武汉城市圈何以堪当“第四极”?
  8. 基于卷积神经网络的手势识别研究论文
  9. secureCRT无法输入
  10. 修复液晶显示器屏幕上的划痕