Classes

  • Dexie

  • DexieError

  • Collection

    • and():Add JS based criteria to collection(向集合添加基于JS的条件)
    • delete():Delete all objects in the collection(删除集合中的所有对象)
    • distinct():Remove duplicates of items with same primary key(删除具有相同主键的项的重复项)
    • modify():Modify all objects in the collection with given properties or function.(使用给定的属性或函数修改集合中的所有对象。)
    • ————————————————————————————————————————————————————————————————————
    • each():Execute query and call a function for each item(执行查询并为每个项调用函数)
    • eachKey():Execute query on the index or primary key being used and call a function for each key(对正在使用的索引或主键执行查询,并为每个键调用函数)
    • eachPrimaryKey():Execute query on the index and call a function for each primary key that corresponds to the index.(对索引执行查询,并为对应于索引的每个主键调用函数。)
    • eachUniqueKey():Execute query on the index or primary key being used and call a function for each unique key(对正在使用的索引或主键执行查询,并为每个唯一键调用函数)
    • ————————————————————————————————————————————————————————————————————
    • toArray():Execute query and get an array with the results sorted by the index used in the where() clause(执行查询并获取一个数组,其结果按where()子句中使用的索引排序)
    • desc():Sort in descending order(按降序排序)
    • reverse():Reverse the order of items.(颠倒项目顺序。)
    • sortBy():Execute query and get an array with the results sorted by given property(执行查询并获取按给定属性排序结果的数组)
    • ————————————————————————————————————————————————————————————————————
    • first():Get the first item in the collection
    • last():Get the last item in the collection(获取集合中的最后一项)
    • limit():Limit the result to given number of items(将结果限制为给定的项目数)
    • offset():Ignore N items before given offset and return the rest(忽略给定偏移量之前的n个项目并返回其余项目)
    • until():Ignores items occurring after given filter returns true.(忽略给定筛选器返回true之后发生的项。)
    • filter():Filter objects
    • ————————————————————————————————————————————————————————————————————
    • keys():Retrieve an array containing all keys of the collection (index or primary key depending on where() clause)(检索包含集合所有键的数组(索引键或主键取决于where()子句))
    • primaryKeys():Retrieve an array containing all primary keys of the collection(检索包含集合的所有主键的数组)
    • uniqueKeys():Retrieve an array containing all unique keys of the collection (index or primary key depending on where() clause)(检索包含集合所有唯一键的数组(索引键或主键取决于where()子句))
    • ————————————————————————————————————————————————————————————————————
    • count():Get the number of items in the collection(获取集合中的项数)
    • or():Logical OR operation
    • raw():Don’t filter results through reading hooks(不要通过阅读挂钩过滤结果)
    • clone():Clone the query before manipulating it further (Does not clone database items).(在进一步操作之前克隆查询(不克隆数据库项)。)
  • IndexSpec

  • Promise

  • Table

    • name:The name of the object store represented by this Table instance.
    • schema:The table schema of this object store.(此对象存储区的表架构。)
    • ————————————————————————————————————————————————————————————————————
    • hook(‘creating’):Atomic CRUD hook called when object is about to be created in db.(当对象将要在数据库中创建时调用)
    • hook(‘reading’):Atomic CRUD hook called when object has been read from db and is about to be delivered to caller.
    • hook(‘updating’):Atomic CRUD hook called when object is about to be modified in db.
    • hook(‘deleting’):Atomic CRUD hook called when object is about to be deleted from db.
    • ————————————————————————————————————————————————————————————————————
    • toArray():Get an array containing all objects in store.(获取包含存储区中所有对象的数组。)
    • limit():Return a Collection ordered by primary key, limited to N items.(返回按主键排序的集合,限制为n个项目。)
    • orderBy():Returns a Collection instance ordered by given index.(返回按给定索引排序的集合实例。)
    • offset():Return a Collection ordered by primary key, where the first N items in the table are ignored.(返回按主键排序的集合,其中表中的前n个项将被忽略。)
    • reverse():Returns a Collection instance with reversed order of the primary key.(返回主键顺序相反的集合实例。)
    • ————————————————————————————————————————————————————————————————————
    • get():Retrieve object by primary key.
    • where():Retrieve objects using a query.(使用查询检索对象。)
    • add():Insert an object into store.
    • bulkAdd():Same as add() but takes array arguments and is optimized for adding a large number of objects.(与add()相同,但接受数组参数,并针对添加大量对象进行了优化。)
    • delete():Delete an object from store.
    • bulkDelete():Same as delete() but takes and array of keys and is optimized for deleting a large number of objects.
    • put():Replace or insert object.(替换或插入对象。)
    • bulkPut():Same as put() but takes array arguments and is optimized for putting a large number of objects.
    • update():Apply given changes to an existing object.(将给定的更改应用于现有对象。)
    • clear():Clear all objects in store.
    • ————————————————————————————————————————————————————————————————————
    • defineClass():Define a javascript constructor function and map to this table.(映射表)
    • mapToClass():Map this table to javascript constructor function.(映射表)
    • count():Count all objects.
    • each():Iterate all objects in store.(迭代存储区中的所有对象。)
    • filter():Apply javascript filter on all items in the object store
    • toCollection():Get a Collection containing all objects in store.(获取包含存储区中所有对象的集合。)
  • TableSchema

  • Transaction

  • Version

  • WhereClause

    • above():Returns a collection of objects where index is above given key(返回索引位于给定键上方的对象集合)
    • aboveOrEqual():Returns a collection of objects where index is above or equal given key(返回索引高于或等于给定键的对象集合)
    • ————————————————————————————————————————————————————————————————————
    • below():Returns a collection of objects where index is below given key(返回索引低于给定键的对象集合)
    • belowOrEqual():Returns a collection of objects where index is below or equal given key(返回索引低于或等于给定键的对象集合)
    • ————————————————————————————————————————————————————————————————————
    • between():Returns a collection of objects where index is between given boundaries(返回索引位于给定边界之间的对象集合)
    • inAnyRange():Returns a collection where index is within any of the given ranges.(返回索引在任何给定范围内的集合)
    • ————————————————————————————————————————————————————————————————————
    • noneOf():Returns a collection where index equals anything but any of the keys in given array(返回一个集合,其中index等于给定数组中的任何键以外的任何值)
    • notEqual():Returns a collection where index equals anything but given value(返回一个集合,其中索引等于给定值以外的任何值)
    • ————————————————————————————————————————————————————————————————————
    • equalsIgnoreCase():Returns a collection of objects where index equals given string-key ignoring case differences(返回一个对象集合,其中索引等于给定的字符串键,忽略大小写差异)
    • equals():Returns a collection of objects where index equals given key(返回索引等于给定键的对象集合)
    • ————————————————————————————————————————————————————————————————————
    • anyOfIgnoreCase():Returns a collection of objects where index matches any of given strings, ignoring case differences.(返回一个对象集合,其中索引与任何给定字符串匹配,忽略大小写差异。)
    • anyOf():Returns a collection of objects where index is equal to any of the keys in given array(返回一个对象集合,其中索引等于给定数组中的任何键)
    • ————————————————————————————————————————————————————————————————————
    • startsWith():Returns a collection of objects where index starts with given string-key(返回以给定字符串键开头的对象集合)
    • startsWithIgnoreCase():Returns a collection of objects where index starts with given string-key ignoring case differences(返回一个对象集合,其中索引以给定的字符串键开头,忽略大小写差异)
    • ————————————————————————————————————————————————————————————————————
    • startsWithAnyOf():Returns a collection of objects where index starts with any of the given strings(返回以任何给定字符串开头的对象集合)
    • startsWithAnyOfIgnoreCase():Returns a collection of objects where index starts with any of given strings, ignoring case differences(返回一个对象集合,其中索引以任何给定字符串开头,忽略大小写差异)

Quick Reference(快速参考)

——————————————————————————————————————————————

整体说明

  • meaning that any operation that requires a result won’t be returned directly. Instead all such operations will return a Promise.(任何需要结果的操作都不会同步返回,所有这样的行为都将返回 Promise)
  • But Dexie gives you a little shortcut in all methods returning a promise with a value, so the above code will be equal to:(Dexie 为所有返回值的异步方法提供了简便方法,可以不写Promise成功时的then而改为回调函数传入方法中)
db.friends.where('name').startsWithIgnoreCase('arnold').toArray().then(function(a) {...})
// 等价于
db.friends.where('name').startsWithIgnoreCase('arnold').toArray(function(a) { // 回调函数传入toArray这个异步方法
console.log(a.length);
}).catch(function(err) {
console.error(err);
});

——————————————————————————————————————————————

安装

npm install dexie --save

——————————————————————————————————————————————

Declare Database(声明数据库)

  • An instance of Dexie will represent a database connection(一个Dexie 实例就是一个database 对象)
  • On your Dexie instance you will have direct access to instances of Table for each object store you have defined in your schema.(在Dexie 实例下可以直接通过属性访问定义好的各个表实例)
  • You only need to specify properties that you wish to index. The object store will allow any properties on your stored objects but you can only query them by indexed properties(只需要指定索引字段,value可以保存任意属性)
  • Never index properties containing images, movies or large (huge) strings. Store them in IndexedDB, yes! but just don’t index them!(不要把任何大数据作为索引对象,包括图片、视频、长字符串)
import Dexie from 'dexie';
var db = new Dexie("MyDatabase");
db.version(1).stores({
friends: "++id, name, age, *tags",
gameSessions: "id, score"
});

Understanding the flow(流程)

  • First time ◦Database is being created(创建数据库)

    • If on(‘populate’) is triggered to populate ground data.(如果有populate,触发填充初始数据)
    • db.open() promise resolves.(db.open()调用then成功)
  • Modify Schema(修改表的架构)

——————————————————————————————————————————————

The populate Event(初始化事件)

  • If database is not present, or an earlier version was present, indexedDB’s onupgradeneeded event is fired and taken care of by Dexie.(如果数据库不存在或传入更高版本号,indexedDB的 onupgradeneeded事件将被触发)
  • IndexedDB is designed for handling database creation and upgrades through the onupgradeneeded event, and define the schema there.(indexeddb设计用于通过onupgradeneeded 事件处理数据库创建和升级,并在其中定义模式。)
  • Dexie adds a declarative schema syntax on top of that so that you don’t need to subscribe to the onupgradeneeded event either.(Dexie添加了一个声明性模式语法,这样您也不需要订阅onupgradened事件。)
  • The database schema is declarative, not imperative.(数据库表架构是声明性的,不是必需的。可以在打开数据库后再创建?)
  • In case your database need initial data in order to work - data that must only be populated on database creation and never more, you can subscribe to the populate event. (如果要在数据库建立时初始化数据可以使用 populate 事件)
  • This will only be called in case the database is initially created - not when it is upgraded.(populate 事件只在建立数据库时调用,更新时不调用)
var db = new Dexie("MyTicketDB");

db.version(1).stores({
tickets: "++id,headline,description,statusId",
statuses: "++id,name,openess"
}); db.on("populate", function() {
// Init your DB with some default statuses:
db.statuses.add({id: 1, name: "opened", openess: true});
db.statuses.add({id: 2, name: "closed", openess: false});
db.statuses.add({id: 3, name: "resolved", openess: false});
db.statuses.add({id: 4, name: "wontfix", openess: false});
});

——————————————————————————————————————————————

Schema Syntax(表模式的语法)

  • ++keyPathAutoincrement primary key(自动增加的主键)
  • ++Hidden autoincremented primary key(隐藏的自动增加的主键)
  • keyPathMeans that primary key can be any type and we have to provide it ourself(主键可以是任意值,新增时需要手动传入)keyPath represents a property name or a dotted path to a nested property.(keypath可以是属性名或嵌套属性的点路径。)
  • (blank)Hidden primary key(隐藏主键?)
  • &keyPathMeans that keyPath is indexed and keys must be unique(索引的值是唯一的)
  • *keyPathMeans that if key is an array, each array value will be regarded as a key to the object.(如果索引的值是一个数组,那么数组中的每一项都能索引到该行数据)This feature lacks support in IE.(此功能在IE中缺乏支持)
  • [keyPath1+keyPath2]Defining a compound index for keyPath1 and keyPath2(以keyPath1 and keyPath2定义复合索引,和and查询相同效果)his feature lacks support in IE.(此功能在IE中缺乏支持)

Indexable Types(可索引类型)

  • Only properties of certain types can be indexed. This includes string, number, Date and Array but NOT boolean, null or undefined. (能索引的类型:字符串、数值、日期、数组。不能索引的类型:布尔、null、undefined)
  • IndexedDB 2.0 contains support for indexing binary data. (IndexedDB 2.0支持二进制数据做为索引)
  • Indexing a property path that turns out to hold a non-indexable type will have no effect. (为一个属性路径建立索引,结果发现该属性路径包含一个不可索引的类型,将不会产生任何效果。)
  • 属性路径,例如:定义索引或主键为a.b,那么这张表就会认为value下的a是一个对象,并且这个对象有个属性b可以作为主键或索引。可以通过a.b这个路径直接操作表

——————————————————————————————————————————————

Class Binding(绑定类)

  • Whichever method you use, your database will return real instances of your mapped class, so that the expression(数据库获取数据操作返回的数据将是这个类的一个实例)
  • mapToClass() - map an existing class to an objectStore(将类映射到表)
class Friend {
// Prototype method
save() {
return db.friends.put(this); // Will only save own props.
} // Prototype property(原型属性)
get age() { // 这里个get 是class中的一个关键字,new Friend().age时会调用该函数
return moment(Date.now()).diff (this.birthDate, 'years'); // moment是一个日期处理库
}
} db.friends.mapToClass(Friend);
  • defineClass() - let Dexie declare a class for you(Dexie声明一个类)
var db = new Dexie("MyAppDB");

db.version(1).stores({
folders: "++id,&path",
files: "++id,filename,extension,folderId"
}); var Folder = db.folders.defineClass({
id: Number,
path: String,
description: String
}); Folder.prototype.save = function () {
return db.folders.put(this);
} var File = db.files.defineClass({
id: Number,
filename: String,
extension: String,
folderId: Number,
tags: [String]
}); File.prototype.save = function () {
return db.files.put(this);
}

——————————————————————————————————————————————

Change Tracking(变动钩子)

  • With Dexie it’s possible to control and monitor each database change.(使用dexie,可以控制和监视每个数据库更改。通过钩子函数)
  • Whenever database is about to be read from or modified, they allow hook implementation to modify what will happen, or just react on the event.(当数据库即将被读取或修改时触发)
  • Hooks Documentation(钩子列表)
    • hook(‘creating’)
    • hook(‘reading’)
    • hook(‘updating’)
    • hook(‘deleting’)

——————————————————————————————————————————————

打开数据库(非必须)

  • Dexie also supports queuing operations, meaning you can start using the database directly after having defined it. In case open() hasn’t been called, it will open it automatically and enqueue the operation to execute as soon as the database is finished opening. (Dexie 支持在实例化后链式调用请求,这些请求支持依序排队执行。这时如果open未被调用,将自动打开数据库执行这些排队任务)
  • If open fails, queued operations will immediately fail with the error event from the open request.(如果打开数据库失败,排队任务也将失败,错误信息显示在oepn方法的Promise.cacth中)
var db = new Dexie("FriendsAndPetsDB");

db.version(1).stores({
friends: "++id,name,isCloseFriend", // 自增主键和索引名
pets: "++id,name,kind"
});
db.open();
db.friends.add({name: "Ingemar Bergman", isCloseFriend: 0});
db.pets.add({name: "Josephina", kind: "dog", fur: "too long right now"});

——————————————————————————————————————————————

Upgrade(升级)

  • 下一个版本会基于上一个版本改变,所以升级时应当保持原有版本的数据库声明不变
  • If no database present, Dexie initializes the last version directly by parsing the stores schema syntax and adding stores and indexes accordingly. No upgrade() functions run in this case.(如果新建数据库,upgrade方法不会被触发)
  • If any error occur in any upgrade function in the sequence, the upgrade transaction will roll back and db.open() will fail. (如果序列中的任何升级函数发生错误,升级事务将回滚,db.open()将失败。)
db.version(1).stores({
friends: "++id,name,age,*tags",
gameSessions: "id,score"
}); db.version(2).stores({
friends: "++id, [firstName+lastName], yearOfBirth, *tags", // Change indexes(改变索引)
gameSessions: null // Delete table(删除表) }).upgrade(tx => {
// Will only be executed if a version below 2 was installed.(当前浏览器数据库版本低于2时触发)
return tx.friends.modify(friend => { // tx.friends返回的是Collection类的实例?
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
friend.birthDate = new Date(new Date().getFullYear() - friend.age, 0);
delete friend.name; // delete是js中删除对象的关键字
delete friend.age;
});
});

——————————————————————————————————————————————

Add Items(添加)

  • 允许存储二级制数据,例如:new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
await db.friends.add({name: "Josephine", age: 21});

await db.friends.bulkAdd([
{name: "Foo", age: 31},
{name: "Bar", age: 32}
]);

——————————————————————————————————————————————

Update Items(更新)

// 替换或新增
await db.friends.put({id: 4, name: "Foo", age: 33}); await db.friends.bulkPut([
{id: 4, name: "Foo2", age: 34},
{id: 5, name: "Bar2", age: 44}
]); // 根据主键更新(更新?)
await db.friends.update(4, {name: "Bar"}); // 根据搜索结果更新
await db.customers
.where("age")
.inAnyRange([ [0, 18], [65, Infinity] ]) // 返回索引在任何给定范围内的集合。
.modify({discount: 0.5}); // 更新

——————————————————————————————————————————————

Delete items(删除)

// 根据主键删除
await db.friends.delete(4); await db.friends.bulkDelete([1,2,4]); // 根据搜索结果删除
const oneWeekAgo = new Date(Date.now() - 60*60*1000*24*7);
await db.logEntries
.where('timestamp').below(oneWeekAgo)
.delete();
  • 去重
db.users.where('email').startsWith('david@').distinct() // 删除具有相同主键的项的重复项?

——————————————————————————————————————————————

Query Items(查询)

  • 尽量不使用传入函数的方法,应该效率会比较低
  • 查询方式有两种
    • Table.get() - retrieve an object by its primary key.(通过主键获取)
    • Table.where() - do an advanced query.(执行高级搜索)
  • Native indexedDB has no support for logical AND or OR operations.(原生indexedDB 不支持and 和 or 查询)
  • Logical OR cannot be done by filtering - we must query the database with two queries to get it.(or 是通过两次查询取并集获得的)
  • We would gain no performance by letting the database handle Logical AND (launching two separate queries and the filter away entries that don’t exist in both collections).(and 通过js过滤性能更好)
var db = new Dexie('music');
db.version(1).stores({
genres: '++id,name',
albums: '++id,name,year,*tracks',
bands: '++id,name,*albumIds,genreId'
}); async function getBandsStartingWithA () {
const bands = await db.bands
.where('name')
.startsWith('A') // 返回以给定字符串键开头的对象集合
.toArray(); await Promise.all (bands.map (async band => { // bands.map返回[promise, ... ]
[band.genre, band.albums] = await Promise.all([
db.genres.get (band.genreId), // 通过主键获取
db.albums.where('id').anyOf(band.albumIds).toArray()
]);
})); return bands;
}
db.users.where('name').startsWithIgnoreCase('da') // 返回一个对象集合,其中索引以给定的字符串键开头,忽略大小写差异

const abcFriends = await db.friends
.where("name")
.startsWithAnyOfIgnoreCase(["a", "b", "c"]) // 返回一个对象集合,其中索引以任何给定字符串开头,忽略大小写差异
.toArray();
await db.customers
.where("age")
.inAnyRange([ [0, 18], [65, Infinity] ]) // 返回索引在任何给定范围内的集合。
.modify({discount: 0.5});
 db.friends
.where('tags')
.equals('close-friend')
.primaryKeys(); // Retrieve an array containing all primary keys of the collection(返回查询结果的所有主键组成的数组)
const someFriends = await db.friends
.where("age").between(20, 25) // 返回索引位于给定边界之间的对象集合
.offset(150) // 忽略给定偏移量之前的n个项目并返回其余项目
.limit(25) // 将结果限制为给定的项目数
.toArray(); // 执行查询并获取一个数组,其结果按where()子句中使用的索引排序
db.friends.toCollection() // 返回表中所有项的集合。
.modify(friend => {
// Modify each friend:
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
delete friend.name;
});
await db.friends
.where("name").equalsIgnoreCase("josephine") // 返回一个对象集合,其中索引等于给定的字符串键,忽略大小写差异
.each(friend => { // 执行查询并为每个项调用函数
console.log("Found Josephine", friend);
});
const friendsContainingLetterA = await db.friends
.filter(friend => /a/i.test(friend.name)) // 筛选对象
.toArray();
await db.friends
.where('age').above(25) // 返回age大于25
.or('shoeSize').below(8) // 返回shoeSize小于8
.or('interests').anyOf('sports', 'pets', 'cars') // 返回一个对象集合,其中索引等于给定数组中的任何键(数组?这个例子有问题吗?)
.modify(friend => friend.tags.push("marketing-target")); // 使用给定的属性或函数修改集合中的所有对象。
db.friends.where('shoeSize')
.between(37, 40)
.or('name')
.anyOf(['Arnold','Ingemar'])
.and(function(friend) { return friend.isCloseFriend; }) // 传入过滤函数返回布尔值
.limit(10)
.each(function(friend){
console.log(JSON.stringify(friend));
});
const best5GameSession = await db.gameSessions
.orderBy("score") // 根据score字段排序
.reverse() // 颠倒项目顺序
.limit(5) // 将结果限制为给定的项目数
.toArray();
const forbundsKansler = await db.friends
.where('[firstName+lastName]')
.equals(["Angela", "Merkel"]) // 返回索引等于给定键的对象集合(复合索引时传入数组,其他传入对应数据类型)
.first(); // 获取集合中的第一项
// In Dexie 2.0, you could do the above query a little simpler:(在新版本中可写为)
const forbundsKansler = await db.friends.where({
firstName: "Angela",
lastName: "Merkel"
}).first();
// 或
const forbundsKansler = await db.friends.get({ // 获取给定primarykey(主键)的对象或满足给定条件(keypath1:value1,keypath2:value2)的对象,并返回第一个匹配结果。
firstName: "Angela",
lastName: "Merkel"
});
// 等价于 select * from friends where firstName='Angela' order by lastName
// order by 排序
const angelasSortedByLastName = await db.friends
.where('[firstName+lastName]')
.between([["Angela", ""], ["Angela", "\uffff"])
.toArray()

——————————————————————————————————————————————

Transaction(事务)

  • 事务可以集合多个数据库操作,这样包裹在函数中的数据库操作就可以实现复用
  • This will not only encapsulate your changes into an atomic operation, but also optimize your code! Internally, non-transactional operations also use a transaction but it is only used in the single operation, so if you surround your code within a transaction, you will perform less costly operations in total.(对数据库的操作都是通过事务完成的,只是分为显示和隐示。把多个操作封装为事务可以时多个操作统一回滚,并且提高性能)
  • If modifying database and any error occur, every modification will be rolled back.(通过事务操作数据库,当出现错误时能够自动回滚)
  • You may do all write operations synchronically without the need to wait for it to finish before starting the next one. (see the 2nd example code below).(可以同步执行所有写操作)
  • Even read-operations can be done the line after a write operations without waiting for write to finish - still your result will include all modifications. This is possible because all operations are queued when there is a pending write operation going on in current transaction.(事务中有写操作时,所有的操作都会排队执行,所以排在后面的读操作能够读取上一条写操作写入的数据)
  • "rw" should be replaced with "r" if you are just going to do read operations.(可以用‘r’替换'rw'如果读数据是只读操作)
await db.transaction('rw', [db.friends], async () => { // 注意:这里事务操作表的声明使用了数组
// 注意这里的事务处理函数使用了异步函数
const friend = await db.friends.get(1);
++friend.age;
await db.friends.put(friend);
});
db.transaction('rw', db.friends, db.pets, function () {  // 注意:这里事务操作表的声明使用了多参数
// 注意这里的事务处理函数使用了同步函数
// MAIN transaction block(主事务)
db.transaction('rw', db.pets, function () { // 事务嵌套,如果父事务回滚了,子事务会回滚吗?
// SUB transaction block(子事务,事务可以嵌套)
});
});
db.transaction('rw', db.friends, function() { // 注意:这里事务操作表的声明使用了单参数
db.friends.add({id:1, name:"Fredrik"});
db.friends.add({id:1, name:"Fredrik"}).catch(function (err) {
// Adding same primary key twice will of course fail. (两次添加相同的主键会失败。)
// But since we catch this error explicitely, the transaction wont abort. (但是,由于我们捕获了这个错误,事务不会中止。)
// This makes it possible to continue the transaction in a managed way.
// If you still want to abort the transaction, just do Dexie.currentTransaction.abort(),(如果你想终止事务请执行Dexie.currentTransaction.abort())
// throw an exception, or just:(重新抛出错误)
// return Promise.reject(err);(返回Promise.reject(err))
});
}).then (function () {
alert ("Transaction successfully completed");
});
  • IndexedDB will commit a transaction as soon as it isn’t used within the same task.(indexeddb将在同一任务中不使用事务时立即提交该事务。)
  • News in Dexie 2.0.0-beta.6: You can now wait for other async APIs and still hold the transaction active, using Dexie.waitFor()(在Dexie 2.0.0-beta.6可以使用Dexie.waitFor()保持事务打开状态,执行非数据库操作的异步方法)
  • Make sure to use the global promise (window.Promise) within transactions. (在事务中只能使用绑定在winodw下的全局Promise)
// 该例子是错误示范,应该先把import库绑定在window上,window.Promise = Promise
// promise-polyfill-of-your-choice是低版本浏览器promise的兼容库
import Promise form 'promise-polyfill-of-your-choice'; db.transaction(..., ()=>{
Promise.all()
Promise.race() // Promise.race([promise1,promise2]) // 其中一个promise返回就会触发Promise.race改变状态
new Promise((resolve, reject) => { ... })
})
  • In the case you write a library (not an app) and you want your library to work on old browsers without requiring a Promise polyfill, it is still safe to use Dexie.Promise:(Dexie内部提供了Dexie.Promise来兼容低版本浏览器)
db.transaction(..., ()=>{
Dexie.Promise.all()
Dexie.Promise.race()
new Dexie.Promise((resolve, reject) => { ... })
})

Exception Handling(异常处理)

  • When you work with transactions, you will also get the benefit of being able to catch all errors in one single place - at the end of the transaction, instead of having to catch() every promise of each database operation. (使用事务时不需要对事务中的所有数据库操作进行错误处理,事务的异常包含内部的所有错误)
  • Any uncatuch error (no matter error events, exception or miss-spelled variable in your code) will abort the ongoing Transaction and trigger its returned Promise to reject, waking up any catch() clause attached to the transaction scope.(任何错误都会终止事务)
  • If you catch a Promise from a database operation within a transaction, it will be considered to be handled and the transaction will not be aborted.(如果在事务中捕获了异常后,事务会认为异常已经被处理,并不会终止事务)
  • If not rethrowing the error, Nils would be successfully added and transaction would commit since the error is regarded as handled when you catch the database operation.(如果没有抛出错误,事务中其他数据库操作会被执行)
  • This could be a common pitfall when people catch promises within transactions just to log it but expecting the transaction to abort. Solution: re-throw the errors that you don’t handle!(如果只是为了记录错误,可以通过重新抛出错误来终止事务)

——————————————————————————————————————————————

疑问

  • db.diary.log 表对象(Table)似乎没有这个方法?
db.transaction('rw', db.friends, db.diary, async () => {
await spreadYourLove(); // spreadYourLove是另一个事务
await db.diary.log({date: Date.now(), text: "Today I successfully spread my love"}); // 这里的log很奇怪?
}).catch (err => {
console.error ("I failed to spread my love :( " + err.stack);
});
  • catch的第一个参数为什么是错误类型?
db.friends.where('name').startsWithIgnoreCase('arnold').toArray(function(a) {
console.log(a.length);
}).catch(DOMError, function(e) {
console.error("DOMError occurred: " + err);
}).catch(TypeError, function(e) {
console.error("TypeError occurred: " + err);
}).catch(function(err) {
console.error("Unknown error occurred: " + err);
}).finally(function(){
console.log("Finally the query succeeded or failed.");
});
  • Dexie Promises supports a pattern similar to Thread-local storage where it is possible to have static properties that is bound to the executing promise and all it’s child-promises. This is similar Angular’s zone.js but in an unobtrusive way (no requirement of including any monkey-patching script). Dexie.js and it’s transaction API heavily depends on it’s transaction zones since it enables code to be aware of the currently executing transaction without having to pass transaction objects around.?

缓存 - 数据缓存 - IndexedDB - Dexie.js的更多相关文章

  1. thinkphp的静态缓存,数据缓存,快速缓存,查询缓存

    // 静态缓存 // 'HTML_PATH' 缓存目录,这是个常量不是配置项,在入口文件中定义 // 'HTML_CACHE_ON'     =>    true, // 开启静态缓存 'HTM ...

  2. .net 数据缓存(一)之介绍

    现在的业务系统越来复杂,大型门户网站内容越来越多,数据库的数据量也越来愈大,所以有了“大数据”这一概念的出现.但是我们都知道当数据库的数据量和访问过于频繁都会影响系统整体性能体验,特别是并发量高的系统 ...

  3. 第十七课:js数据缓存系统的原理

    这一章主要讲的是jQuery的缓存系统的历史发展,以及他自己的框架的缓存系统的实现.都是源码解析. 我就挑几个重点讲下: (1)jQuery的缓存机制的原理 jQuery的缓存机制实现的原理是在元素中 ...

  4. 利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据

    利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据 实现描述:将数据存放在js对象中, 然后放在父页面的document对象中, 在页面刷新的时候将父页面的值取出来, ...

  5. 思索-js 页面ID识别及数据缓存

    思索-页面ID识别及数据缓存 页面 ID 识别的思路 多页应用在移动端是较为常见的一种架构,它可以和APP 内的 webview 配合,达到类似原生的体验,这一点是单页应用无法做到的(比如手势滑动等, ...

  6. 探索前端黑科技——通过 png 图的 rgba 值缓存数据

    本文系原创,欢迎转载,转载请注明作者信息项目地址:SphinxJS在线体验地址:https://jrainlau.github.io/sp... 说起前端缓存,大部分人想到的无非是几个常规的方案,比如 ...

  7. jQuery缓存数据

    很多同学在项目中都喜欢将数据存储在HTMLElement属性上,如 1 2 3 4 <div data="some data">Test</div> < ...

  8. jQuery数据缓存方案详解:$.data()的使用

    我们经常使用隐藏控件或者是js全局变量来临时存储数据,全局变量容易导致命名污染,隐藏控件导致经常读写dom浪费性能.jQuery提供了自己的数据缓存方案,能够达到和隐藏控件.全局变量相同的效果,但是j ...

  9. jQuery 2.0.3 源码分析 数据缓存

    历史背景: jQuery从1.2.3版本引入数据缓存系统,主要的原因就是早期的事件系统 Dean Edwards 的 ddEvent.js代码 带来的问题: 没有一个系统的缓存机制,它把事件的回调都放 ...

随机推荐

  1. Android中使用AlarmManager设置闹钟

    场景 设置闹钟 闹钟提醒 注: 博客: https://blog.csdn.net/badao_liumang_qizhi关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建 ...

  2. redis的基础知识

    select切换数据库 remoteSelf:0>select 0 "OK" dbsize查看当前数据库的key数量 remoteSelf:0>dbsize " ...

  3. 邓士鹏【MySql大全】

    禁止使用系统关键字: typename 1.计算两个日期的时间差函数 SELECT TIMESTAMPDIFF(MONTH,'2009-10-01','2009-09-01'); interval可是 ...

  4. Powershell无文件挖矿查杀方法

    病毒现象 服务器出现卡顿.CPU飙升 和其他主机的445端口,建立起大量的连接 存在大量Powershell进程 病毒处置 封堵445端口; 或打永恒之蓝漏洞补丁(https://wukungt.gi ...

  5. Docker下Jenkins的安装部署、更新

    一.下载Jenkins镜像 docker pull jenkins/jenkins 二.创建挂载文件 mkdir /srv/jenkins chown -R : /srv/jenkins 三.启动Do ...

  6. 正则表达式中的exec()方法

    推荐该博主的内容链接: https://blog.csdn.net/ddwddw4/article/details/84658398?ops_request_misc=%7B%22request%5F ...

  7. 把shp文件处理成Android可以识别中文的版本

    针对ArcGIS10.2版本的解决办法(默认中文编码为OEM): 假设现在有一个shp图层文件“图层.shp”,在ArcGIS10.2中可以正常打开,属性表中有中文内容,以此为例进行设置 1.拷贝一个 ...

  8. LeetCode 面试题 02.02. 返回倒数第 k 个节点

    题目链接:https://leetcode-cn.com/problems/kth-node-from-end-of-list-lcci/ 实现一种算法,找出单向链表中倒数第 k 个节点.返回该节点的 ...

  9. open xml 导出excel遇到的问题

    我有一个需求:使用ajax 下载excel文件 结果:失败 原因:下载文件是通过浏览器解析二级制流下载的,而ajax返回的是文本 方法: 1.如果你下载不需要参数,那直接写个a标签链接到地址就行 2. ...

  10. java.lang.ClassCastException:java.util.LinkedHashMap不能转换为com.testing.models.xxx

    后台接收前台的json字符串 转pojo 问题(Object 对应定义的pojo) ObjectMapper mapper=new ObjectMapper(); Object object = ma ...