async_await函数
# 异步函数
# async function
async关键字用于声明一个异步函数,async异步函数可以有很多种写法
async function foo1(){}
const foo2 = async function(){}
const foo3 = async() => {}
class Person {
async foo(){}
}
2
3
4
5
6
7
8
9
# 异步函数的执行流程
异步函数内部代码执行过程和普通函数是一致的,默认情况下也是会被同步执行
异步函数有返回值时,和普通函数的区别
- 异步函数可以有返回值,但是异步函数的返回值相当于被包裹到Promise.resolve中
- 如果异步函数的返回值是Promise,状态由Promise决定
- 如果异步函数的返回值是一个对象并且实现了thenable,那么会由对象的then方法来决定
如果在async中抛出了异常,那么程序不会像普通函数一样报错,而是会作为Promise的reject来传递
# await 关键字
async函数另外一个特殊之处在于它内部可以使用await
关键字,而普通函数中是不可以使用的
await关键字的特点
- 通常使用await是后面会跟上一个表达式,这个表达式会返回一个Promise
- await会等到Promise的状态变成fulfilled状态,之后继续执行异步函数
- 如果await后面是一个普通的值,那么会直接返回这个值
- 如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值
- 如果await后面的表达式,返回的Promise是reject状态,那么会将这个reject结果直接作为函数的Promise的reject值
# 进程和线程
# 浏览器中的JavaScript线程
经常说JavaScript是单线程(可以开启workers),但是JavaScript的线程应该有自己的容器进程:浏览器或者Node
浏览器的进程和线程
目前多数浏览器都是多进程的,当打开一个tab页面就会开启一个新的进程,这是为了防止一个页面卡死而造成的所有页面无法响应,整个浏览器都要强制退出
每个进程中又有很多线程,其中包括执行JavaScript代码的线程。
JavaScript代码执行是在一个单独的线程中执行的;这就意味着JavaScript代码在同一个时刻只能做一件事;如果这件事是非常耗时的,就意味着当前的线程就会被阻塞
真正耗时的操作实际上并不是由JavaScript线程在执行的;浏览器的每个进程是多线程的,那么其它线程可以来完成这个耗时的操作;比如网络请求,定时器,只需要在特定的时间执行应该有的回调即可
# 浏览器的事件循环
如果在执行JavaScript代码的过程中有异步操作,比如插入一个定时器函数调用,和这个函数会被放到调用栈中,执行会立即结束,并不会阻塞候选代码的执行。
# 宏任务和微任务
时间循环中并非只维护着一个队列,事实上是两个队列
- 宏任务队列(macrotask queue):ajax,setTimeout,DOM监听,UI Rendering等
- 微任务队列(microtask queue):Promise的then回调,Mutatio Observer API,queueMicrotask()等
# 事件循环中对于两个队列的优先级
- main script中的代码优先执行(编写的顶层script代码)
- 在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行;
- 即在宏任务执行之前,必须保证微任务队列是空的;
- 如果不为空,那么优先执行微任务队列中的任务
# Promise面试题
面试题一
console.log("script start");
setTimeout(() => {
console.log("setTimeout1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("then1");
});
setTimeout(function () {
console.log("setTimeout2");
});
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1");
});
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});
console.log("script end");
/*
执行顺序
script start
promise1
2
script end
then1
queueMicrotask1
then3
setTimeout1
then2
then4
setTimeout2
*/
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
37
38
39
40
41
42
43
44
45
46
47
48
49
面试题二
console.log("script start");
function requestData(url) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("setTimeout");
resolve(url);
}, 2000);
});
}
function getData() {
console.log("getData start");
requestData("zs").then((res) => {
console.log("then-res: ", res);
});
console.log("getData end");
}
getData();
console.log("script end");
/*
执行顺序
script start
getDate start
getData end
script end
setTimeout
then-res
*/
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
# 错误处理方案
# throw关键字
throw
表达式就是在throw
后面跟上一个表达式信息来表示具体的异常信息,例如
throw "undefined value"
, throw {code:-001, msg: 'error msg'}
, throw 1
等
# Error类型
JavaScript中提供了一个Error类,可以直接创建这个类的对象
throw new Error('error message', "123")
Error包含三个属性
- message:创建Error对象时传入的message
- name:Error的名称,通常和类的名称一致
- stack:整个Error的错误信息,包括函数的调用栈,当直接打印Error对象时,打印的就是stack
# 异常处理
当函数中一旦抛出了异常,调用它的时候程序会被强制终止,导致后续的代码无法执行
# 异常捕获
很多情况下不希望程序直接退出,而是可以正常的处理异常;这种情况下就可以使用try/catch
try{
} catch () {
> 结论:await后面的代码相当于是在Promise的then回调中执行,即也是在微任务队列中的代码
## Promise async await代码执行过程
} finally {
}
2
3
4
5
6
7
8
9
10
11
12
13
# Storage
WebStorage主要提供了一种机制,可以让浏览器提供一种比cookie更直观的key,value存储方式
- localStorage: 本地存储,提供永久性的存储方法,在关闭掉网页重新打开时,存储的内容依然会被保留
- sessionStorage:会话存储,提供的是本次会话的存储,在关闭会话时,存储的内容会被清除
# localStorage和sessionStorage的区别
- 关闭网页后重新打开,localStorage会保留,sessionStorage会被删除
- 页面内跳转,localStorage会保留,sessionStorage会保留
- 页面外跳转(例如打开新的网页),localStorage会保留,sessionStorage会删除
# Storage常见的属性和方法
属性
Storage.length: 只读属性。返回一个整数,表示存储在Storage对象中的数据项数量
方法
- Storage.key(index): 接收数值n作为参数,返回存储中的第n个key名称
- Storage.getItem(): 接收一个key作为参数,并且返回key对应的value
- Storage.setItem(): 接收一个key和value,并且会把key和value添加到存储中,如果key已经存在,那么更新对应的值
- Storage.removeItem(): 接收一个key作为参数,并把key从存储中删除
- Storage.clear(): 清空存储中的所有key
# 常用工具封装
class Storage {
constructor(isLocal = true) {
this.storage = isLocal ? localStorage : sessionStorage;
}
setItem(key, value) {
if (value) {
this.storage.setItem(key, JSON.stringify(value));
}
}
getItem(key) {
const itemVal = this.storage.getItem(key);
if (itemVal) {
return JSON.parse(itemVal);
}
}
removeItem(key) {
this.storage.removeItem(key);
}
clear() {
this.storage.clear();
}
}
const localCache = new Storage();
const sessionCache = new Storage(false);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25