Micro service recently looking at things and see about communication and data sharing between multiple micro service page solutions, found some relatively unfamiliar API, a strange actually take out specifically can also tell me things, also know what is, but is not skilled, can want to out of thin air is hard to think of, look at the feel some doorways, So I just expanded and sorted it out
BroadcastChannel
Broadcast also means “to Broadcast”, to Broadcast signals so that others can hear them.
This API allows all Windows, iFrames, and so on under the same original domain and user agent to interact, which is homologous communication. That is, if a user opens two tabs on the same site, both tabs will be notified of updates if the site content changes.
For example, A user opens several pages of A website at the same time and logs in on one page. Then, other pages can receive the login status from page A through BroadcastChannel, so that multiple pages can automatically synchronize the login status.
// page A broadcasts signals outward
// Create handle
const cast = new BroadcastChannel('mychannel')
// Data can be any JS data type
const data = 'I\'m from Page A'
// Broadcast signal
cast.postMessage(data)
// Close the connection
cast.close()
Copy the code
// page B listens for "broadcast" from all pages of the same origin.
// BroadcastChannel must be the same as the broadcast source you want to listen on
const cast = new BroadcastChannel('mychannel')
// Receive signal
cast.onmessage = function (e) {
console.log(e.data) // => I'm from Page A
}
// Close the connection
cast.close()
Copy the code
BroadcastChannel is a BroadcastChannel that can send and receive signals to each other as long as it is BroadcastChannel. However, browser support is not very good, and there is no progress in it. I always feel like I’m gonna burp my ass one day
postMessage
otherWindow.postMessage(message, targetOrigin, [transfer]);
PostMessage is a much happier version of BroadcastChannel. It supports cross-domain communication, and browser support has surpassed BroadcastChannel’s to the point of being fully available in production environments. This shows that browser manufacturers are still very keen on this. There’s nothing wrong with capital driving technology
Page A obtains the handle of page B through window.open, sends A signal to page B, and listens for the signal returned by page B
<! -- page A -->
<div id="msg"></div>
<script>
window.onload = (a)= > {
// Get the handle
var opener = window.open('http://127.0.0.1:9001/b.html')
// setTimeout is to wait until the opener handle is actually obtained before sending data
setTimeout((a)= > {
// Only send data signals to pages whose domain name is http://127.0.0.1:9001
opener.postMessage('red'.'http://127.0.0.1:9001');
}, 0)
// listen for the data signal sent back from the clause handle page
window.addEventListener('message', event => {
if(event.origin === 'http://127.0.0.1:9001') {document.getElementById('msg').innerHTML = event.data
}
})
}
</script>
Copy the code
Page B receives the signal from page A and sends the data signal back to page A through the event handle
<div id="box">color from a.html</div>
<script type="text/javascript">
window.addEventListener('message', event => {
// Determine the message source address using the origin attribute
// Only if the data signal comes from the server at http://127.0.0.1:9001
if(event.origin === 'http://127.0.0.1:9001') {// Get the data signal of the operator
document.getElementById('box').style.color = event.data
// Send data back to the source via event.source
event.source.postMessage('got your color! ', event.origin)
}
})
</script>
Copy the code
PostMessage is also relatively easy to use. It is important to note that the API can communicate across domains, and the greater the capability, the greater the responsibility, so there are security issues involved. Generally, when sending and receiving signals, you need to specify the signal source to avoid security issues
In contrast to BroadcastChannel, a postMessage signal is somewhat limited in that it must have a reference to another window in order to continue operations. The source of this reference can be the contentWindow property of iframe, the window object returned by executing window.open, or the window.frames named or numerically indexed. A channel number is not as flexible as an BroadcastChannel
SharedWorker
Web workers are divided into two types: dedicated Web workers and shared Web workers
The Dedicated Web worker ends when the current page closes; This means that a Dedicated Web worker can only be accessed by the page that created it; The corresponding Shared Web worker can be accessed by multiple pages (including multiple tabs and IFrames), but these pages must be homologous, that is, Shared Web workers support homologous communication
Here is a SharedWorker
// worker.js
// Shared data
let shareData = 0
// listen for connections to the main thread
onconnect = function(e) {
const port = e.ports[0]
port.onmessage = function(e) {
if (e.data === 'get') {
// Send a signal to the main thread of the connection
port.postMessage(shareData)
} else {
// Set the data sent by the main thread to the shared data in the worder
shareData = e.data
}
}
}
Copy the code
Set data fields in SharedWorker on page A
<input type="text" id="textInput" />
<input type="button" value="Set up shared Data" />
<script>
const worker = new SharedWorker('worker.js')
const inputEle = document.querySelector('#textInput')
inputEle.onchange = (a)= > {
console.log('Message posted to worker')
// Send a data signal to the worker
worker.port.postMessage(inputEle.value)
}
</script>
Copy the code
B page to obtain data fields in SharedWorker
<div id="result"></div>
<button id="btn">Get the shared data in the SharedWorker</button>
<script>
const worker = new SharedWorker('worker.js')
var result = document.querySelector('#result')
// Send a request to get the shared data in the SharedWorder
document.getElementById('btn').addEventListener('click', () = > {// Send signals to the worker
worker.port.postMessage('get')})// Receive shared data sent from SharedWorder
worker.port.onmessage = e= > {
console.log('Message received from worker')
// Display the obtained worker share data on the page
result.textContent = e.data
}
</script>
Copy the code
Eventually, the values set on page A are retrieved by page B
The worker.js file is loaded separately by page A and page B, but it can share data, similar to the singleton mode. Although the new operator is used, the last two pages get the same thing
Before, I was not familiar with this SharedWorker. I only knew what it was used for, but I didn’t know the details. I always thought it could send signals in one page and receive them automatically in another page, just like BroadcastChannel or postMessge. It’s like two people on the phone, one person talking, the other person doing everything they need to do to hear it right away, and now when they’re done they realize that’s not the case
B page can access to A page set of data, but this is need to take the initiative to operation, not like A phone call, like storage, A page saved A data in public area, want to another page, need to take the initiative to go to get, I am feeling this thing may not be suitable for the page, of course, SharedWorker is not meant to be used for page communication, so it’s understandable that it doesn’t have the desired effect
In addition, when testing SharedWorker, I encountered several pits, which are mentioned here:
- The worker.js script will be cached
When the page loads worker.js for the first time, modify the worker.js file later and refresh the page, it will be found that the worker.js file has not changed and the previous one is still modified. This is because the worker.js file is cached by the browser, and it is useless to force refresh the browser
One solution is to hash the worker.js file, for example:
const worker = new SharedWorker('worker.js? hash=v1')
Copy the code
- The loaded
worker.js
All names must be consistent
According to the above method, the page can update worker.js, but it should also be noted that if the new worker from page A and page B (or more pages) is the same, that is to say, the data can be shared, then the worker.js loaded by these pages not only needs to be the same file, The full name must be identical, including the hash value
In the following case, page A and page B cannot share data, because they load different worker.js hash values, and the singleton mode cannot be established:
// The hash value of page A is V111
const worker = new SharedWorker('worker.js? hash=v111')
// ...
// B page, the hash value is V222
const worker = new SharedWorker('worker.js? hash=v222')
Copy the code
Compared with dedicated Web workers, the browser support of shared web workers is obviously weaker, perhaps because there are more application scenarios of dedicated Web workers than shared web workers. In addition, Microsoft’s Internet Explorer browser and Edge do not support this feature at all, as Microsoft considers the API to be a security issue and is unlikely to support it in the future
Local Storage
Local Storage is used to store data, but because the event Storage exists, it can also monitor the Storage status, so as to achieve the goal of inter-page communication
/ / A page
window.onstorage = function(e) {
console.log(e.newValue); // previous value at e.oldValue
};
/ / B page
localStorage.setItem('key'.'value');
Copy the code
At the beginning, I always thought that the same page can monitor their own storage events, but it didn’t work for a long time. I also searched the MDN document for several times but didn’t find out the reason, and then I finally found the reason on the Internet. The same page cannot listen to its own storage event (like FireFox can listen to its own? It’s almost impossible to write a string that supports page to page communication
websocket
WebSocket is a protocol for full duplex communication on a single TCP connection provided by HTML5. The common scenario is instant communication
To use this technology, both the browser and server must support node.js’s WebSocket solution, known as socket.io
The server side
// index.js
const server = require('http').createServer()
const io = require('socket.io')(server)
io.on('connection', socket => {
socket.on('clientMsg', data => {
// Broadcast is directly broadcast to all connections except the sender
socket.broadcast.emit('serverMsg', data)
})
})
server.listen(3000)
Copy the code
IO package, so remove other unnecessary logic, the main function is to open a socket connection, can receive and broadcast messages, similar to a chat room server
Client code:
<! -- client.html -->
<! -- Message list -->
<ul id="ul"></ul>
<input type="text" id="textInput" />
<button onclick="btnClick()">send</button>
<script>
const socket = io('http://localhost:3000')
// Receive the message sent by the server
socket.on('serverMsg', data => {
addLi(`${data.id}: ${data.msg}`)})const ul = document.getElementById('ul')
const textInput = document.getElementById('textInput')
const id = new Date().getTime()
// Send a message to the server
function btnClick() {
socket.emit('clientMsg', { msg: textInput.value, id })
textInput.value = ' '
}
function addLi(text) {
const li = document.createElement('li')
li.innerText = text
ul.appendChild(li)
}
</script>
Copy the code
In order to cooperate with the server side, we need to introduce the socket.io. Js file on the page to enable the websocket on the browser side:
<script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.js"></script>
Copy the code
After the socket. IO server is started, the client page client. HTML is opened locally, and several more tabs are opened. Each client. HTML is a message receiver
Websocket technology is very mature, can be used in production environment, in addition to a little learning cost, it is not difficult to use, there are no restrictions on the use of a wide range of scenarios, but if it is only page to page communication, using this thing seems to be a bit of a dead end. After all, a dedicated Websocket server can’t run away anyway, right
indexDB
Like LocalStorage, indexDB is used for data storage, but more “specialized”
IndexedDB is a low-level API used to store large amounts of structured data (including files and blobs) on clients. The API uses indexes to perform high-performance searches for this data. Unlike LocalStorage, which stores only strings, IndexedDB can store all types of JS data. Including null, undefined, etc., is a new API in the HTML5 specification
IndexedDB is a way to store large amounts of data using a browser. It creates data that can be queried and used offline. IndexedDB is an effective solution for applications that need to store large amounts of data or that need to be used offline
const request = indexedDB.open('dbBox')
request.onsuccess = function(e) {
console.log('Successfully opened IndexDB')
const myDB = e.target.result
// Start a read-write thing
const transaction = myDB.transaction('person'.'readwrite')
// Get the handle to the person table
const store = transaction.objectStore('person')
// Add two pieces of data to the person table
store.add({name: 'jane'.email:'[email protected]'})
store.add({name: 'kangkang'.email:'[email protected]'})
// All data added successfully, triggering the transaction onComplete event
transaction.oncomplete = function(event) {
// Restart a query transaction
const getResult = myDB.transaction('person'.'readwrite').objectStore('person').get('jane')
getResult.onsuccess= e= > {
console.log('Query result:', e.target.resule)
// => {name: 'jane', email:'[email protected]'}}}}// This event is triggered when the database is opened for the first time or the database version is updated
request.onupgradeneeded = function(e) {
const db = e.target.result
// If the person table does not exist
if(! db.objectStoreNames.contains('person')) {
// Create a new table person
const objectStore = db.createObjectStore('person', {
// specify a primaryKey, similar to a primaryKey, that is used for subsequent database lookups
keyPath: "name"
})
// Create table field name
objectStore.createIndex("name"."name", {
// Specify a field that can be indexed. The unique field is used to specify whether it is unique
unique: true
})
// Create table phone
objectStore.createIndex("phone"."phone", {
unique: false}}})Copy the code
The simple examples above, which include connecting to a database, creating a table, creating a table field structure, adding data, querying data, and so on, are clearly annotated without further explanation
Once done, F12 opens the browser’s console, selects the Application TAB, selects IndexeddDB, and expands to see the stored data
IndexDB as local storage API, there is no global monitoring events, so I can’t for the page, but can be used for data sharing, the API more exclusive terms and concepts involved, may be not so good for the front end of the pure understanding, but as long as it is the computer professional background, for the basic concept of database is able to understand, Essentially nothing, just a simplified version of a local database, right
For indexedDB, browser desktop support is good
webSql
IndexedDB is also a browser database. IndexedDB can be considered as a NoSql database. The operation instructions (add, delete, change, query, etc.) are called in a more “front-end” way, whereas Web SQL is more like a relational database. Examples such as mysql, SQL Server, etc. are more like it, and Web SQL is more like a database than IndexexDB
In addition, the Web SQL database API is not part of the HTML5 specification, but it is a separate specification that introduces a set of APIs for manipulating client databases using SQL. Strangely, though, this stuff doesn’t seem to be persistent storage. After a page refresh, previously stored data, Including database, data table completely drop
// Open a database named mydb, create it if it does not exist, specify the version number as 1.0, the description text of the database as Test DB, and limit the size to 2 * 1024 * 1024
var db = openDatabase('mydb'.'1.0'.'Test DB'.2 * 1024 * 1024)
var msg
// Start the transaction
db.transaction(function (tx) {
// Create a table named LOGS with id and log fields
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)')
// Insert two pieces of data into the table
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, 2)')
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "www.runoob.com")')})// Start transaction
db.transaction(function (tx) {
// Query all data from LOGS table
tx.executeSql('SELECT * FROM LOGS'[],function (tx, results) {
const len = results.rows.length
// Format the result of the query
const rst = Array(len).fill(1).map((v, index) = > results.rows.item(index))
console.log('The list of queried data is:', rst)
}, null)});Copy the code
After doing this, F12 opens the browser’s console, selects the Application TAB, selects Web SQL, and expands to see the stored data
As you can see, there is a lot of SQL in this operation, which is equivalent to learning another SQL language for people who are not familiar with databases. Although it is not difficult to learn basic usage, it is not friendly to front-end programmers. In addition, relational databases appear in the world of JavaScript, which is extremely flexible. There seems to be an incongruity, so the verdict on Web Sql is this:
IndexedDB is an alternative to WebSQL, which was scrapped by the W3C on November 18, 2010. IndexedDB differs from WebSQL in that WebSQL is a relational database (complex) and IndexedDB is a key-value database (simple and efficient).
Before I read this sentence, I thought WebSql was more advanced and IndexedDB should be replaced. However, life is full of surprises
conclusion
Just from the knowledge of micro services to see a point, expansion is an article, really is to learn endless ah. In college, before is more time every day, so happily every day in learning, and come out to learn a new knowledge, joy, now work, every business code written not over, but still need to find time to learn new knowledge, focus on a huge pile of technology, public articles finish see all look not to push every day, The more I know about technology, the more I feel that technology is endless, and I just want to say, please don’t make anything new, I can’t learn anymore and I’m never too old to learn.