目录

async_await函数

# 异步函数

# async function

async关键字用于声明一个异步函数,async异步函数可以有很多种写法

async function foo1(){}

const foo2 = async function(){}

const foo3 = async() => {}

class Person {
    async foo(){}
}
1
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
*/
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
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
*/
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

# 错误处理方案

# 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 {
    
}
1
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);
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
最近更新
01
防抖和节流
02-06
02
正则表达式
01-29
03
迭代器生成器
12-16
更多文章>