使用PouchDB构建离线的第一个应用程序

tech2023-09-10  103

Client-side databases remain a sore spot in cross browser offline application development. In one corner, are Safari and Opera ≤ 12. Both of these browsers support Web SQL exclusively. In the other corner, we have Firefox and Internet Explorer (10+), which support IndexedDB exclusively. Chrome (and Opera 15+), for what it’s worth, supports both.

客户端数据库仍然是跨浏览器离线应用程序开发中的一个痛处。 一个角落是Safari和Opera≤12。这两种浏览器都专门支持Web SQL。 在另一个角落,我们有Firefox和Internet Explorer(10+),它们仅支持IndexedDB。 Chrome(和Opera 15+)值得两者同时支持。

Now this split wouldn’t be so terrible if Web SQL and IndexedDB weren’t radically dissimilar databases with different models for storing data. Supporting both is a nontrivial task. Luckily for us, PouchDB exists.

现在,如果Web SQL和IndexedDB并不是完全不同的具有不同模型来存储数据的数据库,那么这种分裂将不会那么可怕。 同时支持这两个任务并非易事。 对我们来说幸运的是, PouchDB存在。

PouchDB is a client-side database API. It’s written in JavaScript and modeled after the CouchDB API. It’s even capable of synching with a CouchDB instance. We’re interested in PouchDB, however, because it abstracts the differences between Web SQL and IndexedDB, and wraps them in a single interface.

PouchDB是客户端数据库API。 它用JavaScript编写,并以CouchDB API为模型。 它甚至能够与CouchDB实例同步。 但是,我们对PouchDB感兴趣,因为它抽象了Web SQL和IndexedDB之间的差异,并将它们包装在一个接口中。

In this article, we’ll get to know PouchDB by building a simple note taking application that works offline. Only portions of the code will be covered here. Many of the functions have been simplified for readability. You can download the entire thing from GitHub.

在本文中,我们将通过构建一个脱机工作的简单笔记应用程序来了解PouchDB。 这里仅覆盖部分代码。 为了易于阅读,简化了许多功能。 您可以从GitHub 下载整个内容 。

您需要什么 (What You’ll Need)

For this project, you will need the following.

对于此项目,您将需要以下内容。

A copy of the PouchDB script

PouchDB脚本的副本

A web browser that supports IndexedDB or Web SQL. Current versions of Opera, Safari, Internet Explorer, Chrome, and Firefox fit the bill.

支持IndexedDB或Web SQL的Web浏览器。 当前版本的Opera,Safari,Internet Explorer,Chrome和Firefox符合要求。 An HTTP server such as Nginx, Lighttpd, or Apache HTTP.

HTTP服务器,例如Nginx,Lighttpd或Apache HTTP。

It’s not really necessary, but if you’d like to view the data stored in your local database, use a browser with database inspector tools. Chrome, Opera, and Safari all support database inspection with their native developer tools. The following figure shows a PouchDB database in Chrome.

确实不是必需的,但是如果您想查看存储在本地数据库中的数据,请使用带有数据库检查器工具的浏览器。 Chrome,Opera和Safari均通过其本地开发人员工具支持数据库检查。 下图显示了Chrome中的PouchDB数据库。

Because of the origin restrictions baked into IndexedDB and Web SQL, you will also need to use an HTTP server for development. Use whichever server you’d like — Apache, Nginx and Lighttpd are three solid options. Or you can use packages such as MAMP for Mac OS X, WAMP for Windows, or XAMPP for Mac, Windows, and Linux.

由于IndexedDB和Web SQL中的起源限制,您还需要使用HTTP服务器进行开发。 使用你想要的任何服务器- 阿帕奇 , Nginx的和lighttpd的三种固体选项。 或者,您可以使用软件包,例如Mac OS X的MAMP ,Windows的WAMP或Mac,Windows和Linux的XAMPP 。

Add PouchDB to your HTML document as you would any other JavaScript file:

与其他JavaScript文件一样,将PouchDB添加到HTML文档中:

<script src="pouchdb-nightly.min.js"></script>

创建一个PouchDB数据库 (Creating a PouchDB Database)

All PouchDB databases or database connections are created with the PouchDB constructor:

所有PouchDB数据库或数据库连接都是使用PouchDB构造函数创建的:

var pdb = new PouchDB('pouchnotes');

This creates a database named _pouch_pouchnotes. PouchDB prefixes each database name with _pouch_. If you’re also using “raw” IndexedDB or Web SQL for other areas of your web site, avoid using the _pouch_ prefix for those databases.

这将创建一个名为_pouch_pouchnotes的数据库。 PouchDB在每个数据库名称前添加_pouch_ 。 如果您还在网站的其他区域使用“原始” IndexedDB或Web SQL,请避免对这些数据库使用_pouch_前缀。

规划我们的应用 (Planning our application)

So what might a note-taking application look like? Well, we probably want each note to have a title. Each note will also have text that makes up the note’s body. We might want to tag our notes too, so we’ll have a field for that. And wouldn’t it be nice if we were able to attach a file? We’ll use an HTML form such as the one below.

那么做笔记的应用程序是什么样的? 好吧,我们可能希望每个音符都有一个标题。 每个便笺还将包含组成便笺正文的文本。 我们可能也想标记我们的笔记,因此我们将为此添加一个字段。 如果能够附加文件,那不是很好吗? 我们将使用以下HTML表单。

We’ll base our database structure on this form.

我们将基于此表单建立数据库结构。

设计模式(各种) (Designing a Schema (of sorts))

What’s fun about PouchDB is that it has a flexible schema. Each object in the database is really a self-contained document. PouchDB doesn’t use a relational model of data organization, so we can just add fields or properties to a document as we need them.

PouchDB的有趣之处在于它具有灵活的架构。 数据库中的每个对象实际上都是一个独立的文档。 PouchDB不使用数据组织的关系模型,因此我们可以根据需要将字段或属性添加到文档中。

Rather than the SELECT * FROM tablename syntax of SQL/relational databases, PouchDB queries use MapReduce. You write functions to filter and sort your data. It requires a bit of a mental shift when compared to SQL, but it’s easy once you get the hang of it. We’ll see an example of this a little later.

PouchDB查询使用MapReduce,而不是SQL /关系数据库的SELECT * FROM tablename语法。 您编写函数来过滤和排序数据。 与SQL相比,它需要一些思想上的转变,但是一旦掌握了它,这很容易。 我们稍后会看到一个示例。

添加和更新注释 (Adding and Updating Notes)

We’ll add our note to the database when our form is submitted. PouchDB offers two methods for saving a document: post and put. Each method accepts two arguments.

提交表单后,我们会将注释添加到数据库中。 PouchDB提供了两种保存文档的方法: post和put 。 每个方法接受两个参数。

document (required): An object containing properties and their values. In this case, it will be form fields and their values.

document (必填):包含属性及其值的对象。 在这种情况下,它将是表单字段及其值。

callback (optional): A function to call when the operation completes. It accepts two parameters: error and response.

callback (可选):操作完成时要调用的函数。 它接受两个参数: error和response 。

The primary difference is this: post adds a new document and generates an identifier (_id); with put, we need to supply one. This means you can use put to add or update documents. But post is strictly for adding new documents to the database. Now, let’s take a look at an example using put.

主要区别在于: post添加了一个新文档并生成了一个标识符( _id ); 使用put ,我们需要提供一个。 这意味着您可以使用put添加或更新文档。 但是post严格用于向数据库添加新文档。 现在,让我们看一下使用put的示例。

var form, savenote; form = document.getElementById('addnote'); savenote = function(event) { var o = {}; o.notetitle = form.notetitle.value; o.note = form.note.value; o.tags = form.tags.value; /* Generate an _id if we don't have one. It should be a string, which is why we're adding '' to it. */ if (event.target._id.value == '') { o._id = new Date().getTime() + ''; } else { o._id = event.target._id.value; } pdb.put(o, function(error, response) { if (error) { console.log(error); return; } else if(response && response.ok) { /* Do something with the response. */ } }); } /* Add the event handler */ form.addEventListener('submit', savenote);

If there isn’t an _id value in our form, we’ll generate a timestamp to use for it. Otherwise, we’ll use the value of form._id. Our other form fields will become properties and values for our document object. By using put rather than post, we can use our savenote function both to add and update notes.

如果我们的表单中没有_id值,我们将生成一个时间戳以供使用。 否则,我们将使用form._id的值。 我们的其他表单字段将成为文档对象的属性和值。 通过使用put而不是post ,我们可以使用savenote函数添加和更新注释。

If all goes well, our callback will receive a JSON-formatted response. An example of a successful response is shown below.

如果一切顺利,我们的回调将收到JSON格式的响应。 成功响应的示例如下所示。

{ok: true, id: "1391406871281", rev: "1-1d95025598a94304a87ef14c108db7be"}

We haven’t done anything with our response. Depending on your application, you may not want to. But, for our note-taking application, we want the ability to associate a file with a note. PouchDB calls these files attachments.

我们没有做出任何回应。 根据您的应用程序,您可能不想这样做。 但是,对于我们的笔记应用程序,我们希望能够将文件与笔记相关联。 PouchDB将这些文件称为附件 。

保存附件 (Saving Attachments)

Saving an attachment is little more complicated than saving text. We can’t just query the value attribute of the input type="file" field. Instead, we have to read the file data using the File API, then save it using PouchDB’s putAttachment method. Let’s add to our savenote method from the previous section.

保存附件比保存文本复杂得多。 我们不能只查询input type="file"字段的value属性。 相反,我们必须使用File API读取文件数据,然后使用PouchDB的putAttachment方法保存它。 让我们将上一部分添加到我们的savenote方法中。

savenote = function(event) { var o = {}; o.notetitle = form.notetitle.value; o.note = form.note.value; o.tags = form.tags.value; /* Generate an _id if we don't have one. It should be a string, which is why we're adding '' to it. */ if (event.target._id.value == '') { o._id = new Date().getTime() + ''; } else { o._id = event.target._id.value; } pdb.put(o, function(error, response) { if (error) { console.log(error); return; } /* New code for saving attachments */ if (response && response.ok) { if (form.attachment.files.length) { var reader = new FileReader(); /* Using a closure so that we can extract the File's attributes in the function. */ reader.onload = (function(file) { return function(e) { pdb.putAttachment(response.id, file.name, response.rev, e.target.result, file.type); }; })(form.attachment.files.item(0)); reader.readAsDataURL(form.attachment.files.item(0)); } } }); }

Every file input type also has a files attribute that returns a FileList object. In this case, that’s form.attachment.files. As its name suggests, a FileList object is an array containing the file or files submitted using that field. We can determine the number of files in the list with the length property. Each file in the list can be referenced using its index and the item method, as we’ve done here (form.attachment.files.item(0)). Alternatively, you can use square bracket syntax (form.attachment.files[0]).

每种文件输入类型还具有一个files属性,该属性返回FileList对象。 在这种情况下,它是form.attachment.files 。 顾名思义, FileList对象是一个数组,其中包含使用该字段提交的文件。 我们可以使用length属性确定列表中的文件数。 列表中的每个文件都可以使用其索引和item方法进行引用,就像我们在这里所做的那样( form.attachment.files.item(0) )。 另外,您可以使用方括号语法( form.attachment.files[0] )。

If the note is added successfully, we’ll get a response.id. Then, we can check to see whether or not there’s also a file to save as an attachment. If there is, we will read it using a FileReader object (var reader = new FileReader()). PouchDB attachments must be base64-encoded. The easiest way to encode files is to use the readAsDataURL(). Once the file loads, we can save it to the database using putAttachment.

如果注释添加成功,我们将获得response.id 。 然后,我们可以检查是否还有要另存为附件的文件。 如果存在,我们将使用FileReader对象( var reader = new FileReader() )读取它。 PouchDB附件必须是base64编码的。 编码文件的最简单方法是使用readAsDataURL() 。 加载文件后,我们可以使用putAttachment将其保存到数据库中。

PouchDB’s putAttachment method accepts up to six arguments. Five are required, one is optional.

PouchDB的putAttachment方法最多接受六个参数。 五个是必需的,一个是可选的。

docID (required): The identifier for the document that this attachment will be associated with. In this case, it’s response.id.

docID (必填):此附件将与之关联的文档的标识符。 在这种情况下,它是response.id 。

Attachment ID (required): The name of the attachment. Here we’re using the file’s name.

Attachment ID (必填):附件的名称。 在这里,我们使用文件的名称。

rev (required): The parent document’s revision number.

rev (必填):父文档的修订号。

attachment_doc (required): The base64-encoded file data. In this case the result property of our FileReader object.

attachment_doc (必填):base64编码的文件数据。 在这种情况下, FileReader对象的result属性。

type (required): The MIME type for this data. For example, image/png or application/pdf.

type (必填):此数据的MIME类型。 例如, image/png或application/pdf 。

callback (optional): the function to invoke when the operation completes. As with all PouchDB callback functions, it accepts two arguments, error and response. We’ve left it out in our example.

callback (可选):操作完成时要调用的函数。 与所有PouchDB回调函数一样,它接受两个参数error和response 。 在我们的示例中,我们省略了它。

In this example, we also wrapped our onload event handler within a closure. The closure makes it possible to access our file properties from within our event handler (for example, with file.name and file.type).

在此示例中,我们还将onload事件处理程序包装在一个闭包中。 通过闭包,可以从事件处理程序中访问文件属性(例如,使用file.name和file.type )。

Now that we’ve looked at saving notes and attachments, let’s look at retrieving records, both individually and in sets.

现在,我们已经研究了保存便笺和附件,让我们来看一下单独和成组检索记录的方法。

检索所有笔记 (Retrieving All Notes)

What if we want to view a list of the notes in our database? This is where PouchDB’s allDocs is useful. PouchDB.allDocs lets us retrieve a batch of documents at a time.

如果我们想查看数据库中的注释列表怎么办? 这是PouchDB的allDocs有用的地方。 PouchDB.allDocs允许我们一次检索一批文档。

The name allDocs is a bit misleading. We certainly can use it to retrieve all of our documents. However, we can also use it to retrieve documents that fall within a certain range, or retrieve documents that match particular keys. This method accepts two arguments, neither of which are required.

allDocs这个名字有点误导。 我们当然可以使用它来检索我们所有的文档。 但是,我们也可以使用它来检索属于一定范围内的文档,或者检索与特定键匹配的文档。 此方法接受两个参数,都不是必需的。

options (optional): An object containing one or more of the following properties.

options (可选):包含以下一个或多个属性的对象。

include_docs (Boolean): Include the entire document for each row. When false, will only return the document’s id and rev number.

include_docs (布尔值):为每一行包括整个文档。 如果为false ,则仅返回文档的id和rev号。

*

*

conflicts (Boolean): Include conflicts.

conflicts (布尔值):包括冲突。

startkey and endkey: Include documents with keys within this range.

startkey和endkey :包括带有此范围内的键的文档。

descending (boolean): Sort the results in descending order instead.

descending (布尔值):而是按降序对结果进行排序。

*

*

options.keys (array): Return only documents matching the specified keys.

options.keys (数组):仅返回与指定键匹配的文档。

*

*

options.attachments (Boolean): Return attachments with documents.

options.attachments (布尔值):返回带有文档的附件。

*

*

callback (optional): A function to call when when the retrieval completes. As with other PouchDB callbacks, it receives an error argument, and a response argument.

callback (可选):检索完成时调用的函数。 与其他PouchDB回调一样,它接收error参数和response参数。

options (optional): An object containing one or more of the following properties.

options (可选):包含以下一个或多个属性的对象。

In the simplified example below, we’ve retrieved all of the documents in our database. In order to retrieve the document title, created date, and modified date, we need to set the value of include_docs to true. Here’s our viewnoteset function.

在下面的简化示例中,我们检索了数据库中的所有文档。 为了检索文档标题,创建日期和修改日期,我们需要将include_docs的值设置为true 。 这是我们的viewnoteset函数。

var viewnoteset = function() { var df = document.createDocumentFragment(), options = {}, nl = document.querySelector('#notelist tbody'); options.include_docs = true; this.pdb.allDocs(options, function(error, response) { var row = response.rows.map(addrow); // Calls an addrow() function row.map(function(f) { if (f) { df.appendChild(f); } }); nl.appendChild(df); }); };

The value of response is an object containing three properties: total_rows, offset, and rows. We’re most interested in response.rows, since it is an array of document objects. Here we’ve used map, one of JavaScript’s built-in array methods, on response.rows. Using map invokes our addrow function for every note, and adds it to the table that lists our notes.

response的值是一个包含三个属性的对象: total_rows , offset和rows 。 我们对response.rows最为感兴趣,因为它是文档对象的数组。 在这里,我们在response.rows上使用了map ,这是JavaScript的内置数组方法之一。 使用map为每个注释调用我们的addrow函数,并将其添加到列出我们的注释的表中。

检索单个注释 (Retrieving Individual Notes)

Retrieving an individual note is a bit easier, as we can use PouchDB’s get method. The only required argument is the document ID. We can, however, include an options argument and a callback function to handle the results.

检索单个便笺要容易一些,因为我们可以使用PouchDB的get方法。 唯一需要的参数是文档ID。 但是,我们可以包含options参数和回调函数来处理结果。

Our options argument, {attachments: true} ensures that if a particular note has any attachments, it will be shown with the note when viewed. Here, our callback function takes our note data and uses it to fill in our form fields and show any attachment.

我们的选项参数{attachments: true}确保特定注释包含任何附件,并且在查看时将与注释一起显示。 在这里,我们的回调函数获取我们的笔记数据,并使用它来填写表单字段并显示任何附件。

var viewnote = function(noteid) { var noteform = document.querySelector('#noteform'); pdb.get(noteid, {attachments: true}, function(error, response) { var fields = Object.keys(response), o, link, attachments, li; if (error) { return; } else { /* Since our note field names and form field names match, We can just iterate over them. */ fields.map(function(f) { if (noteform[f] !== undefined && noteform[f].type != 'file') { noteform[f].value = response[f]; } if (f == '_attachments') { attachments = response[f]; for (o in attachments) { li = document.createElement('li'); link = document.createElement('a'); link.href = 'data:' + attachments[o].content_type + ';base64,' + attachments[o].data; link.target = "_blank"; link.appendChild(document.createTextNode(o)); li.appendChild(link); } document.getElementById('attachmentlist').appendChild(li); } }); } }); }

In our demo application, we’re passing the id for each note using a link. Each href points to /#/view/xxxxx where xxxxx is the note id. Clicking a link triggers a hashchange event, and the hashchange event handler (shown below) is where we pass the id to viewnote.

在演示应用程序中,我们使用链接传递每个注释的id 。 每个href指向/#/view/xxxxx ,其中xxxxx是注释id 。 单击一个链接将触发一个hashchange事件,而hashchange事件处理程序(如下所示)是我们将id传递给viewnote 。

window.addEventListener('hashchange', function(e) { var noteid; /* Replacing # for compatibility with IE */ if (window.location.hash.replace(/#/,'')) { noteid = window.location.hash.match(/\d/g).join(''); viewnote(noteid); } });

使便笺可搜索 (Making Notes Searchable)

Notes are especially useful when they are searchable. So, let’s add a search feature to our application. We will take input from our search form, and use it as the basis for our search query. The following figure shows what our application will look like when we use the search feature.

便笺在可搜索时特别有用。 因此,让我们向应用程序添加搜索功能。 我们将从搜索表单中获取输入,并将其用作搜索查询的基础。 下图显示了使用搜索功能时我们的应用程序的外观。

PouchDB queries look very different from SQL. With SQL, you specify what to select, from which table, and according to what criteria. For example, a simple note search query might look like this: SELECT * FROM notes WHERE title, text, tags LIKE %interview%. But with PouchDB we run queries using functions.

PouchDB查询看起来与SQL有很大不同。 使用SQL,您可以指定要选择的内容,从哪个表中选择的内容以及根据什么条件。 例如,一个简单的便笺搜索查询可能看起来像这样: SELECT * FROM notes WHERE title, text, tags LIKE %interview% like SELECT * FROM notes WHERE title, text, tags LIKE %interview% 。 但是使用PouchDB,我们使用函数运行查询。

To run a query, we’ll use PouchDB’s query method. It accepts three arguments.

要运行查询,我们将使用PouchDB的query方法。 它接受三个参数。

fun (required): The name of a function.

fun (必填):函数的名称。

options (optional): An object containing options for the search results. You can specify a reduce function or restrict results to a specific key or range of keys.

options (可选):包含搜索结果选项的对象。 您可以指定化简功能或将结果限制为特定的键或键范围。

callback (optional): A function to call when the query completes.

callback (可选):查询完成时要调用的函数。

Let’s look at our search function below.

让我们看看下面的搜索功能。

var search = function(searchkey) { var map = function(doc) { var searchkey, regex; /* Escape characters with special RegExp meaning */ searchkey = document.getElementById('q').value.replace(/[$-\/?[-^{|}]/g, '\\$&'); regex = new RegExp(searchkey,'i'); /* If the notetitle, note, or tags fields match, return only the fields we need to create the result list. */ if (doc.notetitle.match(regex) || doc.note.match(regex) || doc.tags.match(regex)) { emit(doc._id, {notetitle: doc.notetitle, note: doc.note, tags: doc.tags}); } } db.query(map, function(err, response) { if (err) { console.log(err); } if (response) { var df, rows, nl, results; /* Rewrite the response so that our object has the correct structure for our addrow function. */ results = response.rows.map(function(r) { r.doc = r.value; delete r.value; return r; }); nl = document.querySelector('#notelist tbody'); df = document.createDocumentFragment(), rows = results.map(addrow, that); rows.map(function(f) { if (f) { df.appendChild(f); } }); nl.innerHTML = ''; nl.appendChild(df); } }); }

Within our search function, we’ve defined a map function which is how we find and filter our records. The map function always receives a PouchDB document as its sole argument. We don’t have to name this function map, but it must be the first argument.

在搜索功能中,我们定义了一个map功能,这就是我们查找和过滤记录的方式。 map函数始终将PouchDB文档作为其唯一参数。 我们不必命名此函数map ,但它必须是第一个参数。

Within map, we’ve created a regular expression object from our search form input. We’ll test our notetitle, note, and tags fields, to see if any of these fields match our regular expression. If they do, we’ll return the notetitle, id (which is a time stamp), and modified properties using the emit method. The emit method is built into PouchDB. As its name suggests, it selects and returns the properties specified, in the format specified. The first argument of emit becomes the key for our results.

在map ,我们已经从搜索表单输入中创建了一个正则表达式对象。 我们将测试notetitle , note和tags字段,以查看这些字段中的任何一个是否与我们的正则表达式匹配。 如果是这样,我们将使用emit方法返回notetitle , id (这是一个时间戳)和修改后的属性。 该emit方法被内置到PouchDB。 顾名思义,它以指定的格式选择并返回指定的属性。 emit的第一个参数成为我们结果的关键。

Our map function becomes the first argument for query. And the second argument for query is — as you’ve probably guessed — a callback function. Assuming everything went okay, our response argument will be an object containing three properties: total_rows, offset, and rows. We want rows. It’s an array containing the notes that match our search term. The following code sample shows what a response might look like.

我们的map函数成为query的第一个参数。 正如您可能已经猜到的那样, query的第二个参数是回调函数。 假设一切正常,我们的response参数将是一个包含三个属性的对象: total_rows , offset和rows 。 我们要rows 。 它是一个包含与我们的搜索词匹配的注释的数组。 以下代码示例显示了响应的外观。

[{ value: { id: "1388703769529", modified: 1391742787884, notetitle: "Fluffernutter sandwich recipe" }, id:"1388703769529", key:"1388703769529" }, { value: { id: "1391656570611", modified: 1391656570611, notetitle: "Browned-butter Rice Krispie Treats recipe" }, id:"1391656570611", key:"1391656570611" }]

Because our response is an array, we can use native Array.prototype methods to manipulate the results. In this case, we’ve used Array.prototype.map to rewrite each note object so that our value property becomes doc instead, and again to invoke addrow for every result.

因为我们的响应是一个数组,所以我们可以使用本机Array.prototype方法来操纵结果。 在这种情况下,我们使用Array.prototype.map重写每个note对象,以便我们的value属性变为doc ,并再次为每个结果调用addrow 。

脱机使用应用程序缓存 (Working Offline with Application Cache)

To make this application work completely off-line, we also need to save the HTML, CSS, and JavaScript offline using Application Cache. Application Cache is a plain text file, served with a Content-type: text/cache-manifest header that tells the browser which assets to store locally. We won’t do a “deep-dive” on Application Cache here, but let’s look at the manifest file, pouchnotes.cache, for our demo application.

为了使该应用程序完全脱机工作,我们还需要使用Application Cache脱机保存HTML,CSS和JavaScript。 Application Cache是​​一个纯文本文件,带有Content-type: text/cache-manifest标头,用于告知浏览器本地存储哪些资产。 在这里,我们不会对Application Cache进行“深入研究”,而让我们来看一下演示应用程序的清单文件pouchnotes.cache 。

CACHE MANIFEST # Version 2014.02.10.01 CACHE: index.html css/style.css js/pouchdb-nightly.min.js js/application.js

We’ve started it with the line CACHE MANIFEST, which is how all cache manifests must begin. The second line tells us what version of the file this is. Browsers will only update the cache when the cache manifest changes. Changing the version number is the easiest way to trigger an update should we modify our CSS, JavaScript, or HTML files.

我们从CACHE MANIFEST行开始,这是所有缓存清单必须开始的方式。 第二行告诉我们这是什么版本的文件。 浏览器仅在缓存清单更改时才更新缓存。 如果我们修改CSS,JavaScript或HTML文件,更改版本号是触发更新的最简单方法。

We still need to do one more thing, though. We need to add our manifest to our HTML document. That requires adding a manifest attribute to our <html> tag, like this:

不过,我们仍然需要做一件事。 我们需要将清单添加到HTML文档中。 这需要将manifest属性添加到我们的<html>标记中,如下所示:

<html lang="en-us" manifest="pouchnotes.manifest">

Now our database and our files will be available even when we’re offline.

现在,即使我们处于离线状态,我们的数据库和文件也将可用。

Be forewarned: Application Cache adds a layer of development complexity. Because the cache manifest must change in order for the browser to download new files, you should wait until you’re ready to release a version of your application before adding it.

注意:应用程序缓存增加了开发的复杂性。 因为必须更改缓存清单才能使浏览器下载新文件,所以应等到准备发布应用程序的版本之前再添加它。

结论 (Conclusion)

There’s more to PouchDB that we haven’t covered here. For example, you can synchronize PouchDB with a CouchDB server. Synchronizing with a database server lets us build applications that can easily share data and files across multiple browsers and computers.

PouchDB还有更多我们这里没有涉及的内容。 例如,您可以将PouchDB与CouchDB服务器同步。 与数据库服务器同步使我们可以构建可轻松在多个浏览器和计算机之间共享数据和文件的应用程序。

I hope this article has left you with an understanding of what PouchDB is and how you can use it to build software that works even when our Internet connection does not.

我希望本文使您对PouchDB是什么以及如何使用它来构建即使我们的Internet连接不起作用也能运行的软件有所了解。

翻译自: https://www.sitepoint.com/building-offline-first-app-pouchdb/

相关资源:offline-first-project-manager:脱机优先项目管理工具,构建为带有PouchDB,CouchDB和服务工作者的渐进式Web应用程序-源码
最新回复(0)