You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 6-data-storage/03-indexeddb/article.md
+23-23Lines changed: 23 additions & 23 deletions
Original file line number
Diff line number
Diff line change
@@ -40,17 +40,17 @@ let openRequest = indexedDB.open(name, version);
40
40
Podemos tener muchas bases de datos con nombres diferentes, pero todas deben existir dentro del mismo origen (dominio/protocolo/puerto). Un sitio web no puede acceder bases de datos de otro.
41
41
42
42
La llamada devuelve un objeto `openRequest`, debemos escuchar en él los eventos:
43
-
-`success`: la base de datos está lista. Hay un "objeto database" en `openRequest.result`, el que debemos usar en las llamadas que sigan.
43
+
-`success`: la base de datos está lista. Hay un "objeto database" en `openRequest.result`que habremos de usar en las llamadas subsiguientes.
44
44
-`error`: Apertura fallida.
45
45
-`upgradeneeded`: La base de datos está lista, pero su versión es obsoleta (ver abajo).
46
46
47
47
**IndexedDB tiene incorporado un mecanismo de "versión de esquema", ausente en bases de datos de servidor.**
48
48
49
-
Contrario a las bases de datos del lado del servidor, IndexedDB está del lado del cliente y los datos son almacenados en el navegador, así que nosotros, desarrolladores, no tenemos acceso permanente a esas bases. Entonces, cuando publicamos una nueva versión de nuestra app y el usuario visita nuestra página web, podemos necesitar actualizar la estructura de su base de datos.
49
+
A diferencia de las bases de datos del lado del servidor, IndexedDB se ejecuta en el lado del cliente y los datos son almacenados en el navegador, así que nosotros, desarrolladores, no tenemos acceso permanente a esas bases. Entonces, cuando publicamos una nueva versión de nuestra app y el usuario visita nuestra página web, podemos necesitar actualizar la estructura de su base de datos.
50
50
51
51
Si la versión de la base es menor a la especificada en `open`, entonces se dispara un evento especial `upgradeneeded` (actualización-requerida), donde podemos comparar versiones y hacer la actualización de la estructura de datos que se necesite.
52
52
53
-
El evento `upgradeneeded` también se dispara cuando la base aún no existe (técnicamente, su versión es `0`), entonces podemos ejecutar su inicialización.
53
+
El evento `upgradeneeded` también se dispara cuando la base aún no existe (técnicamente, su versión es `0`), lo cual nos permite llevar a cabo su inicialización.
54
54
55
55
Digamos que publicamos la primera versión de nuestra app.
56
56
@@ -82,7 +82,7 @@ Podemos abrirla con version `2` y ejecutar la actualización así:
82
82
let openRequest =indexedDB.open("store", *!*2*/!*);
83
83
84
84
openRequest.onupgradeneeded=function(event) {
85
-
// la versión de la base existente en menor que 2 (o ni siquiera existe)
85
+
// la versión de la base existente es menor que 2 (o ni siquiera existe)
86
86
let db =openRequest.result;
87
87
switch(event.oldVersion) { // versión de db existente
88
88
case0:
@@ -120,7 +120,7 @@ Hablando de versionado, encaremos un pequeño problema relacionado.
120
120
121
121
Supongamos que:
122
122
1. Un visitante, en una pestaña de su navegador, abrió nuestro sitio con un base de datos con la versión `1`.
123
-
2. Luego publicamos una actualización, así que nuestro código en más nuevo.
123
+
2. Luego publicamos una actualización, así que nuestro código es más reciente.
124
124
3. Y el mismo visitante abre nuestro sitio en otra pestaña.
125
125
126
126
Entonces hay una primera pestaña con una conexión abierta a una base con versión `1`, mientras la segunda intenta actualizarla a la versión `2` en su manejador `upgradeneeded`.
1. La escucha a `db.onversionchange` nos informa de un intento de actualización paralela si la conexión actual se volvió obsoleta.
168
-
2. La escucha a `openRequest.onblocked` nos informa la situación opuesta: hay una conexión obsoleta en algún otro lugar que no fue cerrada y por eso la conexión nueva no se pudo realizar.
168
+
2. La escucha a `openRequest.onblocked` nos informa de la situación opuesta: hay una conexión obsoleta en algún otro lugar que no fue cerrada y por eso la conexión nueva no se pudo realizar.
169
169
170
170
Podemos manejar las cosas más suavemente en `db.onversionchange`, como pedirle al visitante que guarde los datos antes de cerrar la conexión.
171
171
@@ -194,9 +194,9 @@ Una clave debe ser de uno de estos tipos: number, date, string, binary, o array.
194
194

195
195
196
196
197
-
De forma similar a `localStorage`, podemos proporcionar una clave cuando agregamos un valor al almacén. Cuando lo que almacenamos son objetos, IndexedDB permite asignar una propiedad del objeto como clave, lo que es mucho más conveniente. También podemos usar claves que se genera automáticamente.
197
+
De forma similar a `localStorage`, podemos proporcionar una clave cuando agregamos un valor al almacén. Cuando lo que almacenamos son objetos, IndexedDB permite asignar una propiedad del objeto como clave, lo que es mucho más conveniente. También podemos usar claves que se generan automáticamente.
198
198
199
-
Pero necesitamos crear el almacén de objetos primero.
199
+
Pero primero, necesitamos crear el almacén de objetos.
200
200
201
201
202
202
La sintaxis para crear un almacén de objetos "object store":
@@ -211,7 +211,7 @@ Ten en cuenta que esta operación es sincrónica, no requiere `await`.
211
211
-`keyPath` -- la ruta a un propiedad de objeto que IndexedDB usará como clave, por ejemplo `id`.
212
212
-`autoIncrement` -- si es `true`, la clave para el objeto nuevo que se almacene se generará automáticamente con un número autoincremental.
213
213
214
-
Si no establecemos `keyOptions`, necesitaremos proporcionar una clave explícitamente luego, al momento de almacenar un objeto.
214
+
Si no establecemos `keyOptions`, necesitaremos proporcionar una clave explícitamente más tarde: al momento de almacenar un objeto.
215
215
216
216
Por ejemplo, este objeto usa la propiedad `id` como clave:
1. Crea una transacción, mencionando todos los almacenes que irá a acceder, en `(1)`.
318
+
1. Crea una transacción, mencionando todos los almacenes a los que irá a acceder, en `(1)`.
319
319
2. Obtiene el almacén usando `transaction.objectStore(name)`, en `(2)`.
320
320
3. Ejecuta lo petición al almacén `books.add(book)`, en `(3)`.
321
-
4. ...Maneja el éxito o fracaso de la petición `(4)`, entonces podemos hacer otras peticiones si lo necesitamos, etc.
321
+
4. ...Maneja el éxito o fracaso de la petición `(4)`, a continuación podemos hacer otras peticiones si lo necesitamos, etc.
322
322
323
323
Los almacenes de objetos soportan dos métodos para almacenar un valor:
324
324
@@ -328,7 +328,7 @@ Los almacenes de objetos soportan dos métodos para almacenar un valor:
328
328
-**add(value, [key])**
329
329
Lo mismo que `put`, pero si ya hay un valor con la misma clave, la petición falla y se genera un error con el nombre `"ConstraintError"`.
330
330
331
-
Al igual que al abrir una base de datos, podemos enviar una petición: `books.add(book)`, y esperar por los eventos `success/error`.
331
+
Al igual que al abrir una base de datos, podemos enviar una petición: `books.add(book)` y quedar a la espera de los eventos `success/error`.
332
332
333
333
- El resultado `request.result` de `add` es la clave del nuevo objeto.
334
334
- El error, si lo hay, está en `request.error`.
@@ -343,13 +343,13 @@ En la siguiente versión 3.0 de la especificación, probablemente haya una maner
343
343
344
344
**Cuando todas las peticiones de una transacción terminaron y la [cola de microtareas](info:microtask-queue) está vacía, se hace un commit (consumación) automático.**
345
345
346
-
Usualmente podemos asumir que una transacción se consuma cuando todas sus peticiones fueron completadas, y el código actual finaliza.
346
+
De forma general, podemos asumir que una transacción se consuma cuando todas sus peticiones fueron completadas y el código actual finaliza.
347
347
348
348
Entonces, en el ejemplo anterior no se necesita una llamada especial para finalizar la transacción.
349
349
350
-
El principio de auto-commit de las transacciones tiene un efecto colateral importante. No podemos insertar una operación asincrónica como `fetch`, `setTimeout` en el medio de la transacción. IndexedDB no mantendrá la transacción esperando a que terminen.
350
+
El principio de auto-commit de las transacciones tiene un efecto colateral importante. No podemos insertar una operación asincrónica como `fetch`, `setTimeout` en mitad de una transacción. IndexedDB no mantendrá la transacción esperando a que terminen.
351
351
352
-
En el código debajo, `request2` en la línea `(*)` falla, porque la transacción ya está finalizada y no podemos hacer más peticiones sobre ella:
352
+
En el siguiente código, `request2` en la línea `(*)` falla, porque la transacción ya está finalizada y no podemos hacer más peticiones sobre ella:
Esto es porque `fetch` es una operación asincrónica, una macrotarea. Las transacciones son cerradas antes de que el navegador comience con las macrotareas.
369
+
Esto es porque `fetch` es una operación asincrónica, una macrotarea. Las transacciones se cierran antes de que el navegador comience con las macrotareas.
370
370
371
371
Los autores de la especificación de IndexedDB creen que las transacciones deben ser de corta vida. Mayormente por razones de rendimiento.
372
372
@@ -376,7 +376,7 @@ Entonces, ¿qué hacer?
376
376
377
377
En el ejemplo de arriba podemos hacer una nueva `db.transaction` justo antes de la nueva petición `(*)`.
378
378
379
-
Pero será mucho mejor, si queremos mantener las operaciones juntas en una transacción, separar las transacciones IndexedDB de la parte asincrónica.
379
+
Pero, si queremos mantener las operaciones juntas en una transacción, será mucho mejor separar las transacciones IndexedDB de la parte asincrónica.
380
380
381
381
Primero, hacer `fetch` y preparar todos los datos que fueran necesarios, y solo entonces crear una transacción y ejecutar todas las peticiones de base de datos. Así, funcionaría.
Solo `complete` garantiza que la transacción fue guardada como un todo. Las peticiones Individuales pueden ser exitosas, pero la operación final de escritura puede ir mal (por ejemplo por un error de Entrada/Salida u otra cosa).
395
+
Solo `complete` garantiza que la transacción fue guardada como un todo. Las peticiones individuales pueden ser exitosas, pero la operación final de escritura puede ir mal (por ejemplo por un error de Entrada/Salida u otra cosa).
396
396
397
397
Para abortar una transacción manualmente:
398
398
@@ -407,7 +407,7 @@ Esto cancela todas las modificaciones hechas por las peticiones y dispara el eve
407
407
408
408
Las peticiones de escritura pueden fallar.
409
409
410
-
Esto es esperable, no solo por posibles errores de nuestro lado, sino también por razones no relacionadas a la transacción misma. Por ejemplo, la cuota de almacenamiento exedida. Entonces debemos estar preparados para manejar tal caso.
410
+
Esto es esperable, no solo por posibles errores de nuestro lado, sino también por razones no relacionadas con la transacción en si misma. Por ejemplo, la cuota de almacenamiento podría haberse exedido. Por tanto, debemos estar preparados para manejar tal caso.
411
411
412
412
**Una petición fallida automáticamente aborta la transacción, cancelando todos sus cambios.**
Hay dos maneras principales de buscar en un almacén de objetos:
481
481
482
-
1. Por clave o por rango de clave. En nuestro almacén "books", puede ser por un valor o por un rando de `book.id`.
482
+
1. Por clave o por rango de claves. En nuestro almacén "books", puede ser por un valor o por un rango de valores de `book.id`.
483
483
2. Por algún otro campo del objeto, por ejemplo `book.price`. Esto requiere una estructura de datos adicional llamada índice "index".
484
484
485
485
### Por clave
@@ -493,7 +493,7 @@ Los objetos `IDBKeyRange` son creados con las siguientes llamadas:
493
493
-`IDBKeyRange.lowerBound(lower, [open])` significa: `≥ lower` (o `> lower` si `open` es true)
494
494
-`IDBKeyRange.upperBound(upper, [open])` significa: `≤ upper` (o `< upper` si `open` es true)
495
495
-`IDBKeyRange.bound(lower, upper, [lowerOpen], [upperOpen])` significa: entre `lower` y `upper`. Si el indicador "open" es true, la clave correspondiente no es incluida en el rango.
496
-
-`IDBKeyRange.only(key)` -- es un rango que consiste de solamente una clave `key`, es raramente usado.
496
+
-`IDBKeyRange.only(key)` -- es un rango compuesto solamente por una clave `key`, es raramente usado.
0 commit comments