Browser Model Overview
How <script> Elements Work
- The browser downloads and parses HTML simultaneously, starting parsing before the download completes.
- Upon encountering a
<script>element, parsing pauses, and control is handed to the JavaScript engine. - If the
<script>references an external file, it is downloaded and executed; otherwise, inline code is executed directly. - After the JavaScript engine finishes, control returns to the rendering engine, resuming HTML parsing.
Browser Rendering Engines
Different browsers use different rendering engines:
- Firefox: Gecko
- Safari: WebKit
- Chrome: Blink
- Internet Explorer: Trident
- Edge: EdgeHTML
Rendering engines process webpages in four stages:
- Parsing: HTML is parsed into a DOM tree, and CSS is parsed into a CSSOM (CSS Object Model).
- Object Synthesis: The DOM and CSSOM are combined into a render tree.
- Layout: The render tree’s layout is calculated.
- Painting: The render tree is painted onto the screen.
Reflow and Repaint
Converting the render tree to a webpage layout is called flow (or layout). Displaying this layout on the page is called paint. Both processes are blocking and resource-intensive.
Script operations, stylesheet changes, and user interactions (e.g., hover effects, scrolling, text input, or resizing windows) can trigger reflow (layout recalculation) and repaint (redrawing). Reflow always triggers repaint, but repaint does not necessarily require reflow. For example:
- Changing an element’s color triggers only repaint.
- Changing an element’s layout triggers both reflow and repaint.
Developers should minimize repaint frequency and cost by:
- Avoiding changes to high-level DOM elements, preferring low-level changes.
- Avoiding expensive layouts like
tableorflex.
Optimization Techniques
- Batch DOM reads and writes together, avoiding interleaving.
- Cache DOM information.
- Change styles using CSS classes instead of individual properties.
- Use
documentFragmentfor DOM operations. - Use
absoluteorfixedpositioning for animations to reduce impact on other elements. - Show/hide elements only when necessary.
- Use
window.requestAnimationFrame()to defer code execution to the next reflow. - Use virtual DOM libraries.
JavaScript Engine
The JavaScript engine reads, processes, and executes JavaScript code in webpages.
JavaScript is an interpreted language, running without compilation. This allows easy execution and modification (e.g., refreshing a page reinterprets code) but incurs higher system overhead and slower performance compared to compiled languages.
Browser JavaScript processing steps:
- Lexical Analysis: Code is broken into tokens.
- Parsing: Tokens are organized into a syntax tree.
- Translation: Code is converted to bytecode.
- Interpretation: Bytecode is translated to machine code.
Common JavaScript engines:
- Chakra (Internet Explorer)
- Nitro/JavaScriptCore (Safari)
- Carakan (Opera)
- SpiderMonkey (Firefox)
- V8 (Chrome, Chromium)
Window Object
Window Object Properties
window.namewindow.closedwindow.openerwindow.selfwindow.windowwindow.frameswindow.lengthwindow.frameElementwindow.topwindow.parentwindow.statuswindow.devicePixelRatio- Position and size properties
- Component properties
- Global object properties
window.isSecureContext
Window Object Methods
window.alert()window.prompt()window.confirm()window.open()window.close()window.stop()window.moveTo()window.moveBy()window.resizeTo()window.resizeBy()window.scrollTo()window.scroll()window.scrollBy()window.print()window.focus()window.blur()window.getSelection()window.getComputedStyle()window.matchMedia()window.requestAnimationFrame()window.requestIdleCallback()
Window Object Events
loadevent andonloadpropertyerrorevent andonerrorproperty- Window event listener properties
Multi-Window Operations
Window References:
top: The topmost windowparent: The parent windowself: The current window
<iframe> Element
window.frames Property
Navigator Object and Screen Object
Navigator Object Properties
Navigator.userAgentNavigator.pluginsNavigator.platformNavigator.onLineNavigator.languageNavigator.languagesNavigator.geolocationNavigator.cookieEnabled
Navigator Object Methods
Navigator.javaEnabled()Navigator.sendBeacon()
Cookies
document.cookie
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnlyXMLHttpRequest Object
XMLHttpRequest Instance Properties
XMLHttpRequest.readyStateXMLHttpRequest.onreadystatechangeXMLHttpRequest.responseXMLHttpRequest.responseTypeXMLHttpRequest.responseTextXMLHttpRequest.responseXMLXMLHttpRequest.responseURLXMLHttpRequest.status,XMLHttpRequest.statusTextXMLHttpRequest.timeout,XMLHttpRequestEventTarget.ontimeout- Event listener properties
XMLHttpRequest.withCredentialsXMLHttpRequest.upload
XMLHttpRequest Instance Methods
XMLHttpRequest.open()XMLHttpRequest.send()XMLHttpRequest.setRequestHeader()XMLHttpRequest.overrideMimeType()XMLHttpRequest.getResponseHeader()XMLHttpRequest.getAllResponseHeaders()XMLHttpRequest.abort()
XMLHttpRequest Instance Events
readyStateChangeeventprogresseventload,error, andaborteventsloadendeventtimeoutevent
Same-Origin Policy
Purpose
The same-origin policy ensures user data security by preventing malicious websites from accessing data. Examples:
http://www.example.com/dir2/other.html: Same originhttp://example.com/dir/other.html: Different origin (different domain)http://v2.www.example.com/dir/other.html: Different origin (different subdomain)http://www.example.com:81/dir/other.html: Different origin (different port)https://www.example.com/dir/page.html: Different origin (different protocol)
Restrictions
- Cannot read
Cookie,LocalStorage, orIndexedDBfrom different origins. - Cannot access the DOM of a different-origin webpage.
- Cannot send AJAX requests to different-origin addresses (requests can be sent, but responses are blocked by the browser).
JavaScript can access another window’s window object. For different origins, only nine properties and four methods are accessible:
window.closed,window.frames,window.length,window.location,window.opener,window.parent,window.self,window.top,window.windowwindow.blur(),window.close(),window.focus(),window.postMessage()
Cookies are server-written data shared only by same-origin pages. If two pages share the same top-level domain but different subdomains, setting document.domain allows cookie sharing.
Cross-Origin Communication
window.postMessage()- JSONP
- WebSocket
- CORS
CORS Communication
CORS (Cross-Origin Resource Sharing) is a W3C standard allowing browsers to send XMLHttpRequest requests to cross-origin servers, bypassing AJAX same-origin restrictions.
CORS requests are categorized as simple requests or non-simple requests.
A request is simple if it meets both conditions:
- The method is one of:
HEAD,GET, orPOST. - Headers are limited to:
Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type(restricted toapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain).
Simple Request
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8Preflight Request
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...Storage Interface
Properties and Methods
Storage.setItem()Storage.getItem()Storage.removeItem()Storage.clear()Storage.key()
window.localStorage.setItem('foo', 'a');
window.localStorage.setItem('bar', 'b');
window.localStorage.setItem('baz', 'c');
window.sessionStorage.setItem('key', 'value');
window.sessionStorage.getItem('key')
sessionStorage.removeItem('key');
localStorage.removeItem('key');
window.sessionStorage.clear()
window.localStorage.clear()
window.localStorage.length // 3Storage Event
The listener function receives an event object inheriting the StorageEvent interface with read-only properties:
StorageEvent.key: The changed key name (string). Returnsnullif triggered byclear().StorageEvent.newValue: The new value (string). Returnsnullif triggered byclear()or key deletion.StorageEvent.oldValue: The old value (string). Returnsnullfor new keys.StorageEvent.storageArea: The storage object containing all key-value pairs for the domain.StorageEvent.url: The URL of the page triggering the storage event.
History Object
Properties
History.length: The number of URLs visited in the current window, including the current page.History.state: The topmost state value in the history stack.
Methods
History.back(): Moves to the previous URL, equivalent to the browser’s back button. No effect on the first URL.History.forward(): Moves to the next URL, equivalent to the forward button. No effect on the last URL.History.go(): Moves to a URL relative to the current one based on an integer parameter (e.g.,go(1)=forward(),go(-1)=back()). No effect if the parameter exceeds the URL range. Default0refreshes the page.History.pushState(): Adds a record to the history.History.replaceState(): Modifies the current history record, identical topushState()otherwise.
Location Object, URL Object, and URLSearchParams Object
Location Object
Properties:
Location.href: The full URL.Location.protocol: The protocol, including the colon (:).Location.host: The host, including port if non-standard (80 or 443).Location.hostname: The hostname, excluding port.Location.port: The port number.Location.pathname: The path, starting with/.Location.search: The query string, starting with?.Location.hash: The fragment identifier, starting with#.Location.username: The username before the domain.Location.password: The password before the domain.Location.origin: The protocol, hostname, and port.
Methods:
Location.assign(): Navigates to a new URL.Location.replace(): Navigates to a new URL without adding to history.Location.reload(): Reloads the current URL.Location.toString(): Returns the full URL, equivalent toLocation.href.
URL Encoding and Decoding
encodeURI()encodeURIComponent()decodeURI()decodeURIComponent()
URL Interface
var url1 = new URL('index.html', 'http://example.com');
url1.href
// "http://example.com/index.html"
var url2 = new URL('page2.html', 'http://example.com/page1.html');
url2.href
// "http://example.com/page2.html"
var url3 = new URL('..', 'http://example.com/a/b.html')
url3.href
// "http://example.com/"Instance Properties:
URL.href: The full URL.URL.protocol: The protocol, ending with:.URL.hostname: The domain name.URL.host: The domain and port, including:(omits default ports 80 and 443).URL.port: The port.URL.origin: The protocol, domain, and port.URL.pathname: The path, starting with/.URL.search: The query string, starting with?.URL.searchParams: AURLSearchParamsinstance (unlikeLocation).URL.hash: The fragment identifier, starting with#.URL.password: The password before the domain.URL.username: The username before the domain.
Static Methods:
URL.createObjectURL()URL.revokeObjectURL()
URLSearchParams Object
URLSearchParams.toString()URLSearchParams.append()URLSearchParams.delete()URLSearchParams.has()URLSearchParams.set()URLSearchParams.get()URLSearchParams.getAll()URLSearchParams.sort()URLSearchParams.keys()URLSearchParams.values()URLSearchParams.entries()
ArrayBuffer Object and Blob Object
ArrayBuffer Object
Represents a segment of binary data, simulating memory data. JavaScript can read and write binary data using this object.
var buf1 = new ArrayBuffer(8);
buf1.byteLength // 8
var buf2 = buf1.slice(0);Blob Object
new Blob(array [, options])
var htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
var myBlob = new Blob(htmlFragment, {type : 'text/html'});
myBlob.size // 32
myBlob.type // "text/html"Retrieving File Information:
// HTML: <input type="file" accept="image/*" multiple onchange="fileinfo(this.files)"/>
function fileinfo(files) {
for (var i = 0; i < files.length; i++) {
var f = files[i];
console.log(
f.name, // Filename without path
f.size, // File size (Blob property)
f.type, // File MIME type (Blob property)
f.lastModifiedDate // Last modified date
);
}
}Downloading Files:
function getBlob(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.onload = function () {
callback(xhr.response);
}
xhr.send(null);
}Generating URLs:
var droptarget = document.getElementById('droptarget');
droptarget.ondrop = function (e) {
var files = e.dataTransfer.files;
for (var i = 0; i < files.length; i++) {
var type = files[i].type;
if (type.substring(0,6) !== 'image/')
continue;
var img = document.createElement('img');
img.src = URL.createObjectURL(files[i]);
img.onload = function () {
this.width = 100;
document.body.appendChild(this);
URL.revokeObjectURL(this.src);
}
}
}Reading Files:FileReader reads Blob or File content:
FileReader.readAsText(): Returns text, defaulting to UTF-8.FileReader.readAsArrayBuffer(): Returns anArrayBuffer.FileReader.readAsDataURL(): Returns a Data URL.FileReader.readAsBinaryString(): Returns a raw binary string.
// HTML: <input type='file' onchange='readfile(this.files[0])'></input>
// <pre id='output'></pre>
function readfile(f) {
var reader = new FileReader();
reader.readAsText(f);
reader.onload = function () {
var text = reader.result;
var out = document.getElementById('output');
out.innerHTML = '';
out.appendChild(document.createTextNode(text));
}
reader.onerror = function(e) {
console.log('Error', e);
};
}// HTML: <input type="file" onchange="typefile(this.files[0])"></input>
function typefile(file) {
var slice = file.slice(0, 4);
var reader = new FileReader();
reader.readAsArrayBuffer(slice);
reader.onload = function (e) {
var buffer = reader.result;
var view = new DataView(buffer);
var magic = view.getUint32(0, false);
switch(magic) {
case 0x89504E47: file.verified_type = 'image/png'; break;
case 0x47494638: file.verified_type = 'image/gif'; break;
case 0x25504446: file.verified_type = 'application/pdf'; break;
case 0x504b0304: file.verified_type = 'application/zip'; break;
}
console.log(file.name, file.verified_type);
};
}File Object, FileList Object, and FileReader Object
File Object
Represents a file for reading and writing. It inherits from Blob and can be used wherever Blob is applicable.
// HTML: <input id="fileItem" type="file">
var file = document.getElementById('fileItem').files[0];
file instanceof File // trueThe native File() constructor creates File instances:
new File(array, name [, options])array: An array of binary objects or strings representing file content.name: A string for the filename or path.options: An optional object for setting instance properties.
Instance Properties and Methods:
File.lastModified: Last modification time.File.name: Filename or path.File.size: File size in bytes.File.type: MIME type.
FileList Object
An array-like object representing selected files, with each member being a File instance. Appears in:
- The
filesproperty of<input type="file">. - The
DataTransfer.filesproperty during drag-and-drop.
// HTML: <input id="fileItem" type="file">
var files = document.getElementById('fileItem').files;
files instanceof FileList // trueFileReader Object
Reads content from File or Blob objects.
Instance Properties:
FileReader.error: Error object from reading.FileReader.readyState: Reading state (0: no data loaded, 1: loading, 2: complete).FileReader.result: File content (string orArrayBuffer).FileReader.onabort: Listener forabortevent.FileReader.onerror: Listener forerrorevent.FileReader.onload: Listener forloadevent, accessing content viaresult.FileReader.onloadstart: Listener forloadstartevent.FileReader.onloadend: Listener forloadendevent.FileReader.onprogress: Listener forprogressevent.
Instance Methods:
FileReader.abort(): Terminates reading, settingreadyStateto 2.FileReader.readAsArrayBuffer(): Reads asArrayBuffer.FileReader.readAsBinaryString(): Reads as raw binary string.FileReader.readAsDataURL(): Reads as Data URL (Base64-encoded).FileReader.readAsText(): Reads as text string, defaulting to UTF-8.
Forms and FormData Object
FormData Object
var formdata = new FormData(form);
var myForm = document.getElementById('myForm');
var formData = new FormData(myForm);
formData.get('username') // ""
formData.set('username', 'John');
formData.get('username') // "John"
formData.set('username', 'John');
formData.append('username', 'Jane');
formData.get('username') // "John"
formData.getAll('username') // ["John", "Jane"]
formData.append('userpic[]', myFileInput.files[0], 'user1.jpg');
formData.append('userpic[]', myFileInput.files[1], 'user2.jpg');
for (var key of formData.keys()) {
console.log(key);
}
for (var value of formData.values()) {
console.log(value);
}
for (var pair of formData.entries()) {
console.log(pair[0] + ': ' + pair[1]);
}
for (var pair of formData) {
console.log(pair[0] + ': ' + pair[1]);
}Instance Methods:
FormData.get(key): Returns the first value for a key.FormData.getAll(key): Returns an array of all values for a key.FormData.set(key, value): Sets a key’s value, adding or updating it. Optional third parameter for filenames.FormData.delete(key): Removes a key-value pair.FormData.append(key, value): Adds a key-value pair, allowing duplicates. Optional third parameter for filenames.FormData.has(key): Returns a boolean indicating if the key exists.FormData.keys(): Returns an iterator for keys.FormData.values(): Returns an iterator for values.FormData.entries(): Returns an iterator for key-value pairs.
Form Validation
Automatic Validation:
<input required>
<input pattern="banana|cherry">
<input minlength="6" maxlength="6">
<input type="number" min="1" max="10">
<input type="email">
<input type="URL">input:invalid {
border-color: red;
}
input,
input:valid {
border-color: #ccc;
}checkValidity():
Manually triggers validation.
form.checkValidity()
formControl.checkValidity()
function submitForm(action) {
var form = document.getElementById('form');
form.action = action;
if (form.checkValidity()) {
form.submit();
}
}willValidate Property:
// HTML: <form novalidate><input id="name" name="name" required /></form>
var input = document.querySelector('#name');
input.willValidate // truevalidationMessage Property:
Returns the browser’s error message for invalid controls.
var myInput = document.getElementById('myinput');
if (!myInput.checkValidity()) {
document.getElementById('prompt').innerHTML = myInput.validationMessage;
}setCustomValidity():
Customizes validation error messages.
<form action="somefile.php">
<input
type="text"
name="username"
placeholder="Username"
pattern="[a-z]{1,15}"
id="username"
>
<input type="submit">
</form>var input = document.getElementById('username');
input.oninvalid = function (event) {
event.target.setCustomValidity(
'Username must be lowercase letters, non-empty, and up to 15 characters'
);
}validity Property:
ValidityState.badInput: Invalid type conversion.ValidityState.customError: Custom error set viasetCustomValidity().ValidityState.patternMismatch: Input does not match pattern.ValidityState.rangeOverflow: Value exceeds maximum.ValidityState.rangeUnderflow: Value below minimum.ValidityState.stepMismatch: Value does not match step.ValidityState.tooLong: Exceeds maximum length.ValidityState.tooShort: Below minimum length.ValidityState.typeMismatch: Invalid type (e.g., email or URL).ValidityState.valid: Meets all validation conditions.ValidityState.valueMissing: Missing required value.
novalidate Attribute:
Disables browser’s automatic validation.
enctype Attribute:
Specifies data encoding for form submission:
application/x-www-form-urlencoded: Default for POST.text/plain: Plain text.multipart/form-data: Mixed format for files.
File Upload
<form method="post" enctype="multipart/form-data">
<div>
<label for="file">Select a file</label>
<input type="file" id="file" name="myFile" multiple>
</div>
<div>
<input type="submit" id="submit" name="submit_button" value="Upload" />
</div>
</form>var fileSelect = document.getElementById('file');
var files = fileSelect.files;
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (!file.type.match('image.*')) {
continue;
}
formData.append('photos[]', file, file.name);
}var xhr = new XMLHttpRequest();
xhr.open('POST', 'handler.php', true);
xhr.onload = function () {
if (xhr.status !== 200) {
console.log('An error occurred!');
}
};
xhr.send(formData);
var file = document.getElementById('test-input').files[0];
var xhr = new XMLHttpRequest();
xhr.open('POST', 'myserver/uploads');
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);IndexedDB API
Overview
IndexedDB stores large data volumes, provides lookup interfaces, and supports indexing, unlike LocalStorage. It is a NoSQL database, not relational, and does not support SQL queries.
Features:
- Key-Value Storage: Uses object stores, supporting all data types, including JavaScript objects. Data is stored as key-value pairs with unique primary keys.
- Asynchronous: Operations do not block the browser, unlike synchronous
LocalStorage. - Transactional: Supports transactions, rolling back on any failure.
- Same-Origin Restriction: Databases are tied to the creating domain.
- Large Storage: Typically at least 250MB, often unlimited.
- Binary Support: Stores strings,
ArrayBuffer, andBlob.
Concepts:
- Database:
IDBDatabase - Object Store:
IDBObjectStore - Index:
IDBIndex - Transaction:
IDBTransaction - Request:
IDBRequest - Cursor:
IDBCursor - Key Range:
IDBKeyRange
Operations
Opening a Database:
var request = window.indexedDB.open(databaseName, version);
request.onerror = function (event) {
console.log('Database open error');
};
request.onsuccess = function (event) {
db = request.result;
console.log('Database opened successfully');
};
request.onupgradeneeded = function (event) {
db = event.target.result;
}Creating a Database:
request.onupgradeneeded = function(event) {
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('person')) {
objectStore = db.createObjectStore('person', { keyPath: 'id' });
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
}
}Adding Data:
function add() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.add({ id: 1, name: 'John', age: 24, email: 'john@example.com' });
request.onsuccess = function (event) {
console.log('Data added successfully');
};
request.onerror = function (event) {
console.log('Data addition failed');
}
}
add();Reading Data:
function read() {
var transaction = db.transaction(['person']);
var objectStore = transaction.objectStore('person');
var request = objectStore.get(1);
request.onerror = function(event) {
console.log('Transaction failed');
};
request.onsuccess = function( event) {
if (request.result) {
console.log('Name: ' + request.result.name);
console.log('Age: ' + request.result.age);
console.log('Email: ' + request.result.email);
} else {
console.log('No data found');
}
};
}
read();Traversing Data:
function readAll() {
var objectStore = db.transaction('person').objectStore('person');
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
console.log('Id: ' + cursor.key);
console.log('Name: ' + cursor.value.name);
console.log('Age: ' + cursor.value.age);
console.log('Email: ' + cursor.value.email);
cursor.continue();
} else {
console.log('No more data!');
}
};
}
readAll();Updating Data:
function update() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.put({ id: 1, name: 'Jane', age: 35, email: 'jane@example.com' });
request.onsuccess = function (event) {
console.log('Data updated successfully');
};
request.onerror = function (event) {
console.log('Data update failed');
}
}
update();Deleting Data:
function remove() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.delete(1);
request.onsuccess = function (event) {
console.log('Data deleted successfully');
};
}
remove();Using Indexes:
var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('Jane');
request.onsuccess = function (e) {
var result = e.target.result;
if (result) {
// ...
} else {
// ...
}
}IndexedDB Objects
indexedDB.open():
var openRequest = indexedDB.open('test', 1);
var db;
openRequest.onupgradeneeded = function (e) {
console.log('Upgrading...');
}
openRequest.onsuccess = function (e) {
console.log('Success!');
db = openRequest.result;
}
openRequest.onerror = function (e) {
console.log('Error');
console.log(e);
}indexedDB.deleteDatabase():
var DBDeleteRequest = window.indexedDB.deleteDatabase('demo');
DBDeleteRequest.onerror = function (event) {
console.log('Error');
};
DBDeleteRequest.onsuccess = function (event) {
console.log('success');
};indexedDB.cmp():
Compares two values as IndexedDB keys, returning 0 (equal), 1 (first > second), or -1 (first < second).
window.indexedDB.cmp(1, 2) // -1IDBRequest Object
Properties:
IDBRequest.readyState:"pending"(operation in progress) or"done"(operation complete).IDBRequest.result: The request result (errors if unavailable).IDBRequest.error: Error object on failure.IDBRequest.source: The request source (e.g., index or object store).IDBRequest.transaction: The current transaction, ornullif none.IDBRequest.onsuccess: Success event listener.IDBRequest.onerror: Error event listener.
IDBOpenDBRequest Properties:
IDBOpenDBRequest.onblocked: Listener forblockedevent (database in use during upgrade).IDBOpenDBRequest.onupgradeneeded: Listener forupgradeneededevent.
IDBDatabase Object
var db;
var DBOpenRequest = window.indexedDB.open('demo', 1);
DBOpenRequest.onerror = function (event) {
console.log('Error');
};
DBOpenRequest.onsuccess = function(event) {
db = DBOpenRequest.result;
// ...
};Properties:
IDBDatabase.name: Database name.IDBDatabase.version: Database version (empty string for new databases).IDBDatabase.objectStoreNames: List of object store names.IDBDatabase.onabort: Listener forabortevent.IDBDatabase.onclose: Listener forcloseevent.IDBDatabase.onerror: Listener forerrorevent.IDBDatabase.onversionchange: Listener for version change events.
Methods:
IDBDatabase.close(): Closes the connection after transactions complete.IDBDatabase.createObjectStore(): Creates an object store (only inversionchange).IDBDatabase.deleteObjectStore(): Deletes an object store (only inversionchange).IDBDatabase.transaction(): Returns anIDBTransaction.
IDBObjectStore Object
Represents an object store, created by IDBDatabase.createObjectStore().
Properties:
IDBObjectStore.indexNames: List of index names.IDBObjectStore.keyPath: Primary key.IDBObjectStore.name: Store name.IDBObjectStore.transaction: Associated transaction.IDBObjectStore.autoIncrement: Boolean for auto-incrementing keys.
Methods:
IDBObjectStore.add()IDBObjectStore.put()IDBObjectStore.clear()IDBObjectStore.delete()IDBObjectStore.count()IDBObjectStore.getKey()IDBObjectStore.get()IDBObjectStore.getAll()IDBObjectStore.getAllKeys()IDBObjectStore.index()IDBObjectStore.createIndex()IDBObjectStore.deleteIndex()IDBObjectStore.openCursor()IDBObjectStore.openKeyCursor()
IDBTransaction Object
var db;
var DBOpenRequest = window.indexedDB.open('demo', 1);
DBOpenRequest.onsuccess = function(event) {
db = DBOpenRequest.result;
var transaction = db.transaction(['demo'], 'readwrite');
transaction.oncomplete = function (event) {
console.log('transaction success');
};
transaction.onerror = function (event) {
console.log('transaction error: ' + transaction.error);
};
var objectStore = transaction.objectStore('demo');
var objectStoreRequest = objectStore.add({ foo: 1 });
objectStoreRequest.onsuccess = function (event) {
console.log('add data success');
};
};Properties:
IDBTransaction.db: The database object.IDBTransaction.error: Transaction error, ornullif not failed or completed.IDBTransaction.mode:"readonly"or"readwrite".IDBTransaction.objectStoreNames: List of involved object stores.IDBTransaction.onabort: Listener forabortevent.IDBTransaction.oncomplete: Listener forcompleteevent.IDBTransaction.onerror: Listener forerrorevent.
Methods:
IDBTransaction.abort(): Terminates and rolls back the transaction.IDBTransaction.objectStore(name): Returns the specified object store.
IDBIndex Object
Represents a database index for retrieving records by non-primary keys.
var transaction = db.transaction(['contactsList'], 'readonly');
var objectStore = transaction.objectStore('contactsList');
var myIndex = objectStore.index('lName');
myIndex.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
var tableRow = document.createElement('tr');
tableRow.innerHTML = '<td>' + cursor.value.id + '</td>'
+ '<td>' + cursor.value.lName + '</td>'
+ '<td>' + cursor.value.fName + '</td>'
+ '<td>' + cursor.value.jTitle + '</td>'
+ '<td>' + cursor.value.company + '</td>'
+ '<td>' + cursor.value.eMail + '</td>'
+ '<td>' + cursor.value.phone + '</td>'
+ '<td>' + cursor.value.age + '</td>';
tableEntry.appendChild(tableRow);
cursor.continue();
} else {
console.log('Entries all displayed.');
}
};Properties:
IDBIndex.name: Index name.IDBIndex.objectStore: Associated object store.IDBIndex.keyPath: Index key.IDBIndex.multiEntry: Boolean for array key paths (each array element indexed iftrue).IDBIndex.unique: Boolean for unique keys.
Methods (all asynchronous, returning IDBRequest):
IDBIndex.count(): Counts records, optionally filtered by key or range.IDBIndex.get(key): Retrieves a record by key.IDBIndex.getKey(key): Retrieves a key.IDBIndex.getAll(): Retrieves all records, optionally filtered.IDBIndex.getAllKeys(): Retrieves all keys.IDBIndex.openCursor(): Traverses index entries with a cursor.IDBIndex.openKeyCursor(): Traverses index keys with a cursor.
IDBCursor Object
Represents a cursor for traversing object stores or indexes.
var transaction = db.transaction(['rushAlbumList'], 'readonly');
var objectStore = transaction.objectStore('rushAlbumList');
objectStore.openCursor(null, 'next').onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
var listItem = document.createElement('li');
listItem.innerHTML = cursor.value.albumTitle + ', ' + cursor.value.year;
list.appendChild(listItem);
console.log(cursor.source);
cursor.continue();
} else {
console.log('Entries all displayed.');
}
};Properties:
IDBCursor.source: The object store or index being traversed.IDBCursor.direction: Traversal direction (next,nextunique,prev,prevunique).IDBCursor.key: Current record’s key.IDBCursor.value: Current record’s value.IDBCursor.primaryKey: Current record’s primary key (equalskeyfor stores, differs for indexes).
Methods:
IDBCursor.advance(n): Moves forwardnpositions.IDBCursor.continue(): Moves forward one position, optionally to a specified key.IDBCursor.continuePrimaryKey(): Moves to a position matching a key and primary key.IDBCursor.delete(): Deletes the current record.IDBCursor.update(): Updates the current record.
IDBKeyRange Object
Represents a range of primary keys for retrieving records.
Static Methods:
IDBKeyRange.lowerBound(): Sets the lower bound.IDBKeyRange.upperBound(): Sets the upper bound.IDBKeyRange.bound(): Sets both bounds.IDBKeyRange.only(): Specifies a single value.
Properties:
IDBKeyRange.lower: Lower bound.IDBKeyRange.lowerOpen: Boolean indicating if the lower bound is exclusive.IDBKeyRange.upper: Upper bound.IDBKeyRange.upperOpen: Boolean indicating if the upper bound is exclusive.
Web Worker
Key Considerations:
- Same-Origin Restriction: Worker scripts must be same-origin as the main thread.
- DOM Restrictions: Workers cannot access the main thread’s DOM,
document,window, orparent, but can usenavigatorandlocation. - Global Object Restrictions: Workers use
WorkerGlobalScope, notWindow. Some interfaces (e.g.,console) are unsupported in theory but often available. - Communication: Workers and the main thread communicate via messages, not direct interaction.
- Script Restrictions: Workers cannot use
alert()orconfirm()but can send AJAX requests. - File Restrictions: Workers cannot access local files (
file://); scripts must be network-loaded.
var worker = new Worker('work.js');
worker.postMessage('Hello World');
worker.postMessage({method: 'echo', args: ['Work']});
worker.onmessage = function (event) {
doSomething(event.data);
}
function doSomething() {
worker.postMessage('Work done!');
}
self.addEventListener('message', function (e) {
self.postMessage('You said: ' + e.data);
}, false);
self.addEventListener('message', function (e) {
var data = e.data;
switch (data.cmd) {
case 'start':
self.postMessage('WORKER STARTED: ' + data.msg);
break;
case 'stop':
self.postMessage('WORKER STOPPED: ' + data.msg);
self.close();
break;
default:
self.postMessage('Unknown command: ' + data.msg);
};
}, false);
worker.onerror(function (event) {
console.log([
'ERROR: Line ', event.lineno, ' in ', event.filename, ': ', event.message
].join(''));
});
worker.terminate();
self.close();Polling with Workers:
function createWorker(f) {
var blob = new Blob(['(' + f.toString() + ')()']);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
return worker;
}
var pollingWorker = createWorker(function (e) {
var cache;
function compare(new, old) { ... };
setInterval(function () {
fetch('/my-api-endpoint').then(function (res) {
var data = res.json();
if (!compare(data, cache)) {
cache = data;
self.postMessage(data);
}
})
}, 1000)
});
pollingWorker.onmessage = function () {
// render data
}
pollingWorker.postMessage('init');Nested Workers:
var worker = new Worker('worker.js');
worker.onmessage = function (event) {
document.getElementById('result').textContent = event.data;
};
// worker.js
var num_workers = 10;
var items_per_worker = 1000000;
var result = 0;
var pending_workers = num_workers;
for (var i = 0; i < num_workers; i += 1) {
var worker = new Worker('core.js');
worker.postMessage(i * items_per_worker);
worker.postMessage((i + 1) * items_per_worker);
worker.onmessage = storeResult;
}
function storeResult(event) {
result += event.data;
pending_workers -= 1;
if (pending_workers <= 0)
postMessage(result);
}
// core.js
var start;
onmessage = getStart;
function getStart(event) {
start = event.data;
onmessage = getEnd;
}
var end;
function getEnd(event) {
end = event.data;
onmessage = null;
work();
}
function work() {
var result = 0;
for (var i = start; i < end; i += 1) {
result += 1;
}
postMessage(result);
close();
}



