CookieStore API
Currently, browsers can store cookie
/sessionStorage
/localStorage
/IndexedDB
, all of which expose a very developer friendly API, except for cookies. Think back to how we normally manipulate cookies. For example, if you want to retrieve a cookie, you have to parse it manually to get the value of a cookie because document.cookie
returns a string that is the union of all cookies.
If you want to add a cookie, then you need to convert the cookie to a string and assign it to document.cookie
as below.
Isn’t it strange that document.cookie
is a collection of all cookies, but adding a cookie is a direct assignment to document.cookie
? Another oddity is that sometimes adding a cookie doesn’t work at all, but the browser doesn’t give any error messages, so you have to use getCookie
after setCookie
to see if it works.
However, deleting a cookie is even stranger, as we cannot just delete it, but let it expire.
A new CookieStore API has been introduced based on the above issues.
First, a cookieStore
object is added to the window, and then get/set/delete
methods are mounted on the cookieStore
object for the get/add/delete
operations of a single cookie. Note that get/set/delete
all return a Promise
, so exceptions need to be handled.
|
|
|
|
The cookieStore also provides the getAll
method, which is used to obtain a list of cookies.
|
|
Previously, the only way to listen for cookie changes was to check for them at regular intervals using a timer, but cookieStore
provides the ability to listen for cookie changes directly.
Compatibility and reference
Media Session API
If you want to control audio
/video
on a page, you can only do so by using the browser’s own control component or by implementing your own control component, and you will not be able to control audio
/video
when the page is unclickable (e.g. switching to another tab or minimizing the browser window).
The Media Session API
exposes control of the page audio
/video
, enabling the system media centre to control the page audio
/video
, including basic information about the media being played (title/author/cover) and actions (play/pause/fast forward/fast rewind/next media/previous media).
|
|
The above example implements a basic MediaSession
. The basic information is instantiated by the global object MediaMetadata
, where artwork
can be set to multiple values, and the browser automatically selects the best size for the scene, which is then assigned to navigator.mediaSession.metadata
. Media control is set via the navigator.mediaSession.setActionHandler
method, with play
/pause
/seekbackward
/seekforward
/previoustrack
/nexttrack
corresponding to play
/pause
/nexttrack
respectively. play/
pause/
seekbackward/
seekforward/
previoustrack/
nexttrack` operations. Once the media has been played, the browser maps the basic information and actions to the system and provides the corresponding action menus in the system.
Under Windows 10, for example, the Media Control Panel appears near the volume control.
On Android, the Media Control Panel will appear in the status bar.
The Media Control Panel also appears in the header of some browsers.
Compatibility and reference
Shape Detection API
QR codes are everywhere nowadays, but recognising them on the web is not an easy task, either by uploading them to the backend for parsing or by using complex JS libraries. The new BarcodeDetector
feature provides a user-friendly API to recognize QR codes locally without the backend.
To use BarcodeDetector
you first need to instantiate it, and then pass the image data to the detect
method of the instance, which is an asynchronous operation, so the return value is a Promise
. Also, a single image may contain multiple QR codes, so the result is an array.
|
|
BarcodeDetector
not only recognises 2D codes, but also supports various barcode formats, including aztec
/ code_128
/ code_39
/ code_93
/ codabar
/ data_matrix
/ ean_13
/ ean_8
/ itf
/ pdf417
/ qr_code
/ upc_a
/ upc_e
. BarcodeDetector
recognises all barcode formats by default, if you only want to recognise certain formats, you can specify this when instantiating:
The BarcodeDetector
is part of the Shape Detection API
, in addition to the TextDetector
and the FaceDetector
, which correspond to text recognition and face recognition respectively, the following is an example of text recognition
TextDetector
is not yet stable, so it may not be able to recognize text on canvas, and uploaded images may not be recognized accurately.
|
|
Compatibility and reference
- Can I use
- Accelerated Shape Detection in Images
- The Shape Detection API: a picture is worth a thousand words, faces, and barcodes
Top-level await
Previously the await
keyword was only allowed inside the async function
, top-level await
allows us to use the await
keyword directly outside the async function
.
Use the script above top-level await
to directly remove the async function
.
If a module uses top-level await
, then other modules that refer to it will wait for it to resolve
.
In the above code, the output order is 1 2 react
, which means that the b module will wait for the a module to resolve
before it continues to execute. Similarly, when the a module reject
, the b module will not work properly. For the b module to work properly, an error handler needs to be added to the a module.
|
|
The top-level await
is ideal for certain scenarios.
Conditional introduction of modules
We know that static import
does not allow for conditional import, for example the following code is not legal.
Conditional static imports can be simulated by using top-level await
in conjunction with dynamic import
.
Dependency fallback
When we introduce a static module, if the module fails to load, then all other modules that reference it will not work properly.
Dependency fallback can be achieved with top-level await
and dynamic import
.
Resource initialization
Previously, when a resource needed to be initialized asynchronously, it was usually written in the following way.
Note that the above code is only an example, there is a lot of error handling required in practice
In the above code, the synchronous sendMessage
method is forced to become asynchronous by the asynchronous getWs
method, which can be avoided by using top-level await
.
Compatibility and reference
BigInt
In JavaScript, the range of integers is [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]
, which is from the 53rd power of minus 2 minus 1 to the 53rd power of 2 minus 1, outside of which precision is not guaranteed, for example:
If you want to accurately represent integers beyond SAFE_INTEGER, it is common to convert them to strings and then implement various string operations (I’m sure many of you have done the algorithm for adding strings of numbers, e.g. '123' + '789' = '912'
).
BigInt
can represent an arbitrarily large integer, even if it is outside the range of SAFE_INTEGER
, to ensure precision. A BigInt
can be declared by adding n
to the number or by using the BigInt
method:
The above a
/ b
/ c
all represent 123n
. BigInt
supports the +
/ -
/ *
/ /
/ **
/ %
operators, but cannot be mixed with other types:
|
|
BigInt
can be converted to number, and if BigInt
exceeds the range of SAFE_INTER
, then the converted number will lose precision:
BigInt
also supports comparison operations, and can be compared with number:
BigInt
also has some limitations, firstly it does not support calling methods on Math
objects, and secondly it does not support JSON.stringify
, so if you want to serialize it, you can implement the toJSON
method of BigInt
:
Note that BigInt
is a normal method like Symbol
, not a constructor, so it cannot be instantiated by new
:
|
|
JavaScript has 7 data types
undefined
/null
/boolean
/number
/string
/symbol
/object
,BigInt
is the 8th data type, the value oftypeof 1n
isbigint
, and is a basic type.
Compatibility and reference
Number separators
Often, if a number is unusually large, we add separators to the display to make it more readable:
is now usually a thousand-digit separator, supposedly derived from the English thousond/million/billion/trillion/…, with a proper noun for each additional 3 digits (https://en.wikipedia.org/wiki/Namesoflarge_numbers). For me it’s more of a ten-thousand separator, probably because I got used to it in primary school maths.
But at JavaScript level, we can only concatenate numbers no matter how big they are, e.g. 1032467823482.32134324
, which requires careful counting to get the exact value.
Now, the Numeric separators
feature allows the insertion of _
separators between numeric literals to make them more readable.
_
The separator can appear in the integer part, or in the decimal part. In addition to decimal, separators can also appear in other decimal systems
The above code adds separators every 3 digits, however, it is important to note that separators can only be added between numbers, not at the beginning/end of numbers/binary symbols/decimal points/scientific notation, and not two separators in a row, as the following separator positions are wrong.
The number separator is only there to improve readability and has no real meaning; numbers with a separator are converted to strings without the separator. Similarly, strings with _
are not converted to numbers correctly
In addition, the number separator also applies to the BigInt
mentioned above.
Compatibility and references
New syntax for CSS colour methods
There are 4 colour methods
in CSS, rgb
/ rgba
/ hsl
/ hsla
. Previously, the arguments to each method were separated by a comma
, but now the new syntax for rgb
/ hsl
allows the comma
to be omitted and the arguments to be separated by a space
.
While omitting the comma, rgb
/ hsl
both support the 4th parameter, indicating transparency, thereby replacing rgba
and hsla
.
Where, the spaces on either side of /
are optional.
Compatibility and references
aspect-ratio
If you want to achieve a rectangle with a specified ratio, you usually use padding
, which takes advantage of the fact that the percentage is calculated based on the width of the parent element, but the real content often needs to be placed in an additional child element and absolute positioning needs to be set:
|
|
The aspect-ratio
property allows us to set the aspect ratio of an element directly. The example above using aspect-ratio
would look like this
Compatibility and reference
gap
The grid-gap
property can be used to set row-to-row and column-to-column gaps in the grid
layout, but now the gap
property can be used directly instead of grid-gap
, and the gap
property adds support for flex
and column-count
.
|
|
Compatibility and reference
CSS math functions
The calc
method can be used to perform mathematical calculations in CSS, and now there are three new methods min
/ max
/ clamp
.
The min
method takes one or more values and returns the smallest of them, e.g. width: min(1vw, 4rem, 80px);
, if the width of viewport
is equal to 800px
, then 1vw === 8px
, 4rem === 64px
, so the result is width: 1vw;
.
The max
method takes one or more values and returns the maximum of them, in the example above, the result is width: 80px;
.
The clamp
method takes 3 values clamp(MIN, VAL, MAX)
, from left to right they are min/preferred/max values, if the preferred value is less than the min value then the min value is returned, if it is greater than the max value then the max value is returned, if the preferred value is between the min and max values then the preferred value is returned, the logic can be expressed in JS like this
That is, clamp
limits the range of values of VAL
, e.g. width: clamp(1rem, 10vw, 2rem);
where the width of viewport
is equal to 800px
, the result is width: 2rem;
, because (10vw = 80px) > (2rem = 32px)
.
Interestingly, min
/ max
/ clamp
can also be nested with other methods, such as clamp(1rem, calc(10vw - 5px), min(2rem, 20vw))
, so clamp
can be written as max(MIN, min(VAL, MAX))
or min(MAX, max (VAL, MIN))
.