We usually use document.cookie for operations such as adding, deleting, and checking cookies. Here we introduce a new method cookieStore.

1. How to manipulate cookies in general

document.cookie gets all the cookie strings for the current domain. Each cookie is separated by a semicolon.

1
document.cookie; // "a=1; b=2; c=wenzi"

To manipulate cookies, you are generally manipulating document.cookie.

Here is a piece of code that I commonly use.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * 写cookies
 * @param {string} name 写cookie的key
 * @param {string|number} value 写cookie的值
 * @param {number} day 存储的时间,默认30天
 */
export const setCookie = (name: string, value: string | number, day = 30): void => {
  const exp = new Date();
  exp.setTime(exp.getTime() + day * 24 * 60 * 60 * 1000);
  document.cookie = `${name}=${escape(value.toString())};path=/;expires=${exp.toUTCString()}`;
};

/**
 * 读取cookies
 * @param {string} name 要获取的cookie名称
 * @param {number|boolean} type 是否直接获取对应的值,若存入真值,则直接返回,否则进行解码
 */
export const getCookie = (name: string): string | null => {
  const reg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
  const arr = document.cookie.match(reg);
  if (arr) {
    return unescape(arr[2]);
  }
  return null;
};

/**
 * 删除cookie
 * @param name 删除的cookie名称
 */
export const delCookie = (name: string) => {
  if (!name) return;
  const ex: Date = new Date();
  ex.setTime(ex.getTime() - 1);
  document.cookie = `${name}=; expires=${ex.toUTCString()};path=/`;
};

You can see that setting, getting and deleting cookies are all done on document.cookie.

2. New method cookieStore

Chrome now has a more convenient way to manipulate cookies, cookieStore, which was added in Chrome version 87 and is not yet compatible.

Below is an overview of compatibility as of 2021/03/15, and you can see that only Chrome supports cookieStore.

sobcookieStorete

But let’s start by understanding how it’s used.

The cookieStore can now only be accessed by domains under the https protocol; other http protocol domains will indicate that the cookieStore is undefined, or that the setting has failed.

2.1 Basic methods

A cookieStore is an object type variable like localStorage.

localStorage

You can see that the cookieStore has 5 main methods.

  • set: sets the cookie, either set(name, value), or set({name, value}).
  • get: Gets the cookie, either get(name), or get({name});
  • getAll: Gets all cookies.
  • delete: delete the cookie.
  • onchange: listens for changes to the cookie.

The first 4 methods are naturally Promise enabled, so let’s go through them one by one.

2.2 Setting cookies

The cookieStore.set method sets the cookie and returns a Promise state indicating whether it was set successfully.

1
2
3
4
cookieStore
  .set('username', 'wenzi')
  .then(() => console.log('设置username成功'))
  .catch(() => console.error('设置username失败'));

cookieStore

If we want to set more properties, such as the expiration time, we can pass in an Object type.

1
2
3
4
5
6
7
8
cookieStore
  .set({
    name: 'age',
    value: 18,
    expires: new Date().getTime() + 24 * 60 * 60 * 1000,
  })
  .then(() => console.log('设置age成功'))
  .catch(() => console.error('设置age失败'));

cookieStore

All the data in value will be executed by default toString() first, and then stored, so some non-basic types of data, it is better to convert first.

The above are the cases when we set the cookie successfully, but when does it fail? In the localhost environment, the setting will fail.

In localhost, we can get the cookieStore global variable and execute the corresponding methods, but we can’t set it successfully.

1
cookieStore.set('username', 'wenzi');

The browser will indicate that the cookie cannot be set via the set in the CookieStore under an insecure domain.

1
Uncaught (in promise) TypeError: Failed to execute 'set' on 'CookieStore': Cannot modify a secure cookie on insecure origin

The error is caught by adding the catch statement.

1
2
3
4
cookieStore
  .set('username', 'wenzi')
  .then(() => console.log('设置username成功'))
  .catch(() => console.error('设置username失败'));

cookieStore

Therefore, when you want to use the cookieStore, you can’t determine it directly in the following way. A new page url protocol must be added to determine this.

1
typeof cookieStore === 'object'; // 判断不准确,本地localhost也会存在

Should be used.

1
const isSupportCookieStore = typeof cookieStore === 'object' && location.protocol === 'https:'; // 只有在https协议下才使用cookieStore

The cookieStore.get(name) method gets the cookie corresponding to the name and returns all properties in Promise format

1
await cookieStore.get('username');

cookieStore

The get() method can also receive an Object type, and after testing, we found that the value of key can only be name.

1
await cookieStore.get({ name: 'username' });

Returns a Promise<null> when the fetched cookie does not exist.

2.4 Getting all cookies

The cookieStore.getAll() method gets all the current cookies, returned as a Promise<[]>, with each item in the array in the same format as the one obtained by get(); if there are no cookies in the current domain, or if the specified cookie is not obtained, the array is empty.

1
await cookieStore.getAll();

cookieStore

The getAll() method can also pass in a name to get the corresponding cookie.

1
2
await cookieStore.getAll('username');
await cookieStore.getAll({ name: 'username' });

2.5 Deleting cookies

cookieStore.delete(name) is used to delete the specified cookie.

1
2
3
4
cookieStore
  .delete('age')
  .then(() => console.log('删除age成功'))
  .catch(() => console.error('删除age失败'));

If the deletion is successful, the deletion will be indicated as successful.

Even if a non-existent cookie is deleted, it will still prompt for a successful deletion. Therefore, when the above code is executed again, it will still prompt normally.

Similarly, in a localhost environment, the deletion will fail.

2.6 Listening for changes to cookies

We can listen to changes in the cookie by adding change events, either through cookieStore operations or directly on document.cookie.

Add a listener event.

1
2
3
4
5
6
cookieStore.addEventListener('change', (event) => {
  const type = event.changed.length ? 'change' : 'delete';
  const data = (event.changed.length ? event.changed : event.deleted).map((item) => item.name);

  console.log(`刚才进行了 ${type} 操作,cookie有:${JSON.stringify(data)}`);
});

There are 2 important fields changed array and deleted array, when setting a cookie, the changed array is the cookie just set; when deleting a cookie, the deleted array is the cookie just deleted.

2.6.1 Set operations

When the set() method is called, the change event is triggered and the affected cookies are placed in the event.changed array.

A cookie set or deleted by document.cookie is considered to be a modified cookie, not a deleted one.

The change event is triggered every time a cookie is set, even if the name and value are exactly the same twice.

1
cookieStore.set('math', 90);

cookieStore

As you can see, when the cookie with the name math is deleted for the second time, the change event is not triggered.

3. Summary

We have learned about the use and operation of the cookieStore, which is much easier than manipulating cookies directly, and we can listen to changes in cookies through our own change events.