事件循环顺序

  • 微任务(MicroTask):微/小的意思:可以理解为相对没那么费时没那么慢的任务
    • Promise / MutationObserver / process.nextTick (node独有)
  • 宏任务(MacroTask):宏/大的意思,可以理解为比较费时比较慢的任务
    • SetTimeout / setInterval / setImmediate (IE独有)

从上至下先执行所有同步代码,微任务和宏任务都放到对应的执行队列中,然后执行微任务,最后执行宏任务。

注意:每执行完一个宏任务都会立刻检查微任务队列有没有被清空,如果又产生了新的那么会立即执行。

AJAX

AJAXA是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下更新部分页面。

1.创建异步对象 new XMLHttpRequest()

2.设置请求方式和请求地址 .open(method,url,async)

  • method:请求的类型:GET 还是 POST
  • url:服务器(文件)位置
  • async:true(异步)或 false(同步)

3.发送请求 send()

4.监听状态的变化

5.处理返回的结果

GET请求

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
<button>请求数据</button>

<script>
var myBtn = document.querySelector("button");
myBtn.onclick = function () {
//1.创建异步对象
var xmlhttp = new XMLHttpRequest();
//2.设置请求
xmlhttp.open("GET", "https://api.vvhan.com/api/60s?type=json", true)
//3.发送请求
xmlhttp.send();
//4.监听状态的变化
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4) {
if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status === 304) {
let sj = xmlhttp.responseText; //接收返回的数据
console.log(sj);
console.log("请求成功,执行的代码"); //处理返回的结果
} else {
console.log("请求失败,未接收到服务器数据");
}
}

}

}
</script>

POST请求

如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader() 来添加 HTTP 头(放在open和send之间)。然后在 send() 方法中规定您希望发送的数据。

1
2
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("name=zs&lname=18");

示例

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
<button>请求数据</button>

<script>
var myBtn = document.querySelector("button");
myBtn.onclick = function () {
//1.创建异步对象
var xmlhttp = new XMLHttpRequest();
//2.设置请求
xmlhttp.open("POST", "https://api.vvhan.com/api/60s?type=json", true)

xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//3.发送请求
xmlhttp.send("name=zs&lname=18");
//4.监听状态的变化
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4) {
if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status === 304) {
let sj = xmlhttp.responseText; //接收返回的数据
console.log(sj);
console.log("请求成功,执行的代码"); //处理返回的结果
} else {
console.log("请求失败,未接收到服务器数据");
}
}

}

}
</script>

封装GET和POST

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
//封装
function myAjax(type, url, timeout, success, error) {
//1.创建对象
var xmlhttp = new XMLHttpRequest();
//2.设置请求
xmlhttp.open(type, url, true)
//3.发送请求
xmlhttp.send();
//4.监听状态的变化
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4) {
if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status === 304) {
success(xmlhttp);
} else {
error(xmlhttp);
}
}

}

//5.判断外界是否传入了超时时间
if (timeout) {
timer = setInterval(function () {
console.log("中断请求");
xmlhttp.abort(); //中断请求
clearInterval(timer); //清除定时器
}, timeout)
}

}


//使用
var myBtn = document.querySelector("button");
myBtn.onclick = function () {
myAjax("GET", "https://api.vvhan.com/api/60s?type=json", 3000, function (xhr) {
console.log(xhr.responseText);
console.log("请求成功的代码");
}, function (xhr) {
console.log("请求失败的代码");
})
}

JSON

1
2
3
4
JSON.parse()	//将一个 JSON 字符串转换为 JavaScript 对象。
JSON.stringify() //用于将 JavaScript 值转换为 JSON 字符串。

eval() //将一个非标准的字符串转换为js对象

JSON 数据:一个名称对应一个值;JSON 数据格式为 键/值 对,就像 JavaScript 对象属性。;键/值对包括字段名称(在双引号中),后面一个冒号,然后是值。

1
"name":"Runoob"

JSON 对象:JSON 对象保存在大括号内。就像在 JavaScript 中, 对象可以保存多个 键/值 对:

1
{"name":"Runoob", "url":"www.runoob.com"}

JSON 数组:JSON 数组保存在中括号内。就像在 JavaScript 中, 数组可以包含对象。

1
2
3
4
5
6
7
"sites":[
{"name":"Runoob", "url":"www.runoob.com"},
{"name":"Google", "url":"www.google.com"},
{"name":"Taobao", "url":"www.taobao.com"}
]

//以上实例中,对象 "sites" 是一个数组,包含了三个对象。每个对象为站点的信息(网站名和网站地址)。

将网页中的数据保存到电脑中。菜鸟教程

  • 生命周期:默认情况下是一次会话(浏览器被关闭); 通过 expires= 可以设置过期时间
  • 注意点:默认不会保存任何数据
    • 不能一次设置多条数据,只能一条一条设置
    • 个数限制20/50,建议20以内;大小限制4KB左右
  • 作用范围:同一个浏览器的同一个路径下访问。
    • 下一级路径也可以访问
    • 上一级路径不可以访问,一般通过
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//添加cookie
document.cookie = "moren = tianjia";

//添加cookie有效期
var date = new Date();
date.setDate(date.getDate() + 7);
document.cookie = "youxiaoqi=7tian;expires=" + date.toGMTString() + ";"

//添加cookie有效路径
document.cookie = "lujing = path;path=/"

//添加cookie有效域名
document.cookie = "yuming=domain;domain=han8.net"


//查询cookie 全部返回,无法单个查询
document.cookie;

//修改cookie
document.cookie = "moren = xiugai";

//删除cookie
document.cookie = "moren= ; expires=Thu, 01 Jan 1970 00:00:00 GMT";

cookie 封装

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
//添加cookie 封装
function addCooKie(key, value, day, path, domain) {

//1.处理默认保存的路径
var index = window.location.pathname.lastIndexOf("/");
var currentPath = window.location.pathname.slice(0, index);
path = path || currentPath

//2.处理默认保存的domain
domain = domain || document.domain;

//3.处理默认的过期时间
if (!day) {
document.cookie = `${key}=${value};path=${path};domain=${domain};`;
} else {
var date = new Date();
date.setDate(date.getDate() + day);
document.cookie = `${key}=${value};expires=${date.toGMTString()};path=${path};domain=${domain};`;
}
}

//获取单个cookie 封装
function getCookie(key) {
var res = document.cookie.split(";"); //得到cookie全部转换为一个数组
for (var i = 0; i < res.length; i++) {
var temp = res[i].split("="); //得到单个的数组[key,value]
if (temp[0].trim() === key) { //trim() 清除空格
return temp[1];
} //如果单个数组中索引0===,那么就返回索引1的值
}
}

//删除单个cookie 封装 注意:只能删除当前域名下的cookie
function delCookie(key) {
document.cookie = `${key}= ; expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;`;
}

////////////////////////////////////////////////////////使用

//添加-后三个可省略,采用默认
addCooKie("name", "zs", 2, "/", "han8.net");
//获取
getCookie("name");
//删除
delCookie("name");

hash

hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)

1
2
3
4
//种hash
window.location.hash = 2;
//获取hash值
console.log(window.location.hash.substring(1)); //window.loaction.hash 得到的是#2,需要截取去掉#

sessionStorage 和 localStorage

会话存储本地存储

cookie sessionStorage localStorage
生命周期 关闭浏览器失效,可设置时间 关闭窗口失效,不能设置过期时间 永久保存
容量 大小4kb左右,个数20-50 大小限制5M左右 大小限制5M左右
网络请求 每次都会携带在HTTP头中 仅在浏览器中保存,不参与服务器通信 仅在浏览器中保存,不参与服务器通信
应用场景 判断用户是否登录 表单填写 购物车
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 保存数据到
sessionStorage.setItem('key', 'value');
localStorage.setItem('key', 'value');

//获取数据
let data = sessionStorage.getItem('key');
let data = localStorage.getItem('key');

//删除数据
sessionStorage.removeItem('key');
localStorage.removeItem('key');

//删除所有数据
sessionStorage.clear();
localStorage.clear();

进程 线程 串行 并行

什么是进程?

  • 进程是指程序在操作系统中的一次执行过程, 是系统进行资源分配和调度的基本单位

什么是线程?

  • 线程是指进程中的一个执行实例, 是程序执行的最小单元, 它是比进程更小的能独立运行的基本单位。一个进程中至少有一个线程, 这个线程我们称之为主线程。一个进程中除了主线程以外, 我们还可以创建和销毁多个线程

什么是串行?

  • 串行就是按顺序执行, 就好比银行只有1个窗口, 有3个人要办事, 那么必须排队, 只有前面的人办完走人, 才能轮到你。在计算机中, *同一时刻, 只能有一条指令, 在一个CPU上执行, 后面的指令必须等到前面指令执行完才能执行*, 就是串行
  • JS中的代码都是串行的,前面没有执行完毕后面不能执行。

什么是并行?

  • 并行就是同时执行, 就好比银行有3个窗口, 有3个人要办事, 只需要到空窗口即可立即办事。在计算机中, *同一时刻, 有多条指令, 在多个CPU上执行*, 就是并行。从以上分析不难看出, 并行的速度优于串行

什么是并发?

  • 并发是伪并行, 就好比银行只有1个窗口, 有3个人要办事, 那么没轮到后面的人时, 后面的人可以用拖鞋先排队, 去吃个早餐,买个东西啥的, 感觉差不多要到自己时再回来办事。在计算机中, ***同一时刻, 只能有一条指令, 在一个CPU上执行, 但是CPU会快速的在多条指令之间轮询执行***就是并发
  • 多线程程序在单核上运行, 就是并发
  • 多线程程序在多核上运行,就是并行

js中的同步代码和异步代码:

  • 除了“事件绑定的函数”和“回调函数”以外的代码都是同步代码
  • 程序运行会从上至下依次执行所有的同步代码;在执行的过程中如果遇到异步代码会将异步代码放到时间循环中;当所有同步代码都执行完毕之之后,js会不断检测 事件循环中的代码是否满足条件;一旦满足条件就执行满足条件的异步代码。

Promise

Promise 是ES6中新增的异步编程解决方案,在代码中的表现是一个对象。通过Promise就可以实现,用同步的流程来表示异步的操作,可以避免回调函数层层嵌套的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建Promise对象
let bl = new Promise(function(resolve,reject){
console.log("Promise对象不是异步的");
console.log("立即执行这里存放的代码");
})

//Promise有三种状态,只要状态改变就会自动触发对应的函数
// pending 默认; fulfilled(resolved)成功 ; rejected 失败

let zz = new Promise(function(resolve,reject){
resolve();
})
//resolve => then()
zz.then(function(){
console.log("执行这里的代码");
});
//rejected => catch();
zz.catch(function(){
console.log("不执行");
})

Promise - then 方法

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//then方法可以接收两个参数,成功函数 失败函数
var bl = new Promise(function (resolve, reject) {
resolve();
})
bl.then(function () {
console.log("成功状态执行这里的代码");
}, function () {
console.log("失败状态执行这里的代码");
});


//修改Promise状态时,可以传递参数给then方法中的回调函数
var bl = new Promise(function (resolve, reject) {
resolve("111");
});
bl.then(success, error);

function success(data) {
console.log("成功状态", data);
}

function error(data) {
console.log("失败状态", data);
}


//同一个Promise可以多次调用,都会被执行
var bl = new Promise(function (resolve, reject) {
resolve();
})
bl.then(function () {
console.log("成功1");
}, function () {
console.log("失败1");
});
bl.then(function () {
console.log("成功2");
}, function () {
console.log("失败2");
}); //输出:成功1 成功2


//每次执行完毕后会返回一个新的Promise对象
var bl = new Promise(function (resolve, reject) {
resolve();
})
var blNEW = bl.then(function () {
console.log("成功1");
}, function () {
console.log("失败1");
});
console.log(blNEW); //Promise {<pending>}
console.log(bl === blNEW); //false


//可以通过上一个promise对象的then方法给下一个promise对象的then方法传递参数
//注意:无论是上一个promise对象成功还是失败的回调传递的参数,都会传递给下一个promise对象成功的回调
var bl1 = new Promise(function (resolve, reject) {
resolve("111111");
})
var bl2 = bl1.then(function (data) {
console.log("成功1", data);
return "9999999";
}, function (data) {
console.log("失败1", data);
});
bl2.then(function (data) {
console.log("成功2", data);
}, function (data) {
console.log("失败2", data);
}); //输出:成功1 111111 成功2 9999999


//如果then方法返回的是一个promise对象,那么会将返回的prommise对象的执行结果中的值传递给下一个then方法
var bla = new Promise(function (resolve, reject) {
resolve("aaa");
});
var blb = new Promise(function (resolve, reject) {
resolve("bbb");
});
var blc = bla.then(function (data) {
console.log("成功2", data);
return blb;
}, function (data) {
console.log("失败2", data);
});
blc.then(function (data) {
console.log("成功3", data);
}) // 成功2 aaa ; 成功3 bbb

Promise - catch 方法

1
2
3
4
5
6
7
8
9
10
11
12
//catch 其实时 then(undefined,()=>()}的语法糖,只能监听失败状态
var bl = new Promise(function(resolve,reject){
reject();
})
//链式编程
bl.then(function(){
console.log("成功执行");
}).catch(function(){
console.log("失败执行");
})

//其它特点和then一样,参考同上

Promise.all 和 Promise.race

Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。all方法接受一个数组;如果数组中有多个Promise对象,谁先返回失败状态就听谁的,后返回的会被抛弃;如果数组中不是Promise对象,那么会直接执行then方法。

1
2
3
4
5
6
7
8
9
10
11
var p = Promise.all([p1,p2,p3]);
//数组内的每个元素都成功,p才会成功;谁先失败,谁就先传递给p

let p1 = Promise.resolve("P1-OK");
let p2 = Promise.reject("P2-NOT-OK");
let p3 = Promise.resolve("P3-OK");
let p = Promise.all([p1, p2, p3]);
console.log(p);
p.then(null, function (s) {
console.log(s)
});//P2-NOT-OK

Promise.race 方法也是接受一个数组;如果数组中有多个Promise对象,谁的状态先改变就听谁的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("p1-ok");
}, 4000);
});
let p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
reject("p2-not-ok");
}, 500);
});
let p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("p3-ok");
}, 3000);
});
//失败 p2-not-ok
Promise.race([p1, p2, p3]).then(function (value) {
console.log("成功", value);
}).catch(function (e) {
console.log("失败", e);
});

fetch

和AJAX一样都是用于请求网络数据的;fetch是ES6中新增的,基于Promise的网络请求方法。

1
fetch(url,{options}).then().catch();
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
//get请求-----------------------
fetch("https://www.ghxi.com/wp-json/wp/v2/posts", {
method: "get" //get请求如果需要传参,直接添加到url后面即可 ?name=zs&age=18
}).then(function (a) {
console.log("成功拿到数据,下面拿到对象");
return a.json(); //json()返回结果和JSON.parse(responseText)一样;text()将返回体处理成字符串类型
}).then(function (b) {
console.log(b);
}).catch(function (z) {
console.log(z);
});

//post请求-----------------------
fetch("https://www.ghxi.com/wp-json/wp/v2/posts", {
method: "post",
body: JSON.stringify({
name: "zs",
age: 18
}) //post如果需要传参,写到对象中
}).then(function (a) {
console.log("成功拿到数据,下面拿到对象");
return a.json(); //json()返回结果和JSON.parse(responseText)一样;text()将返回体处理成字符串类型
}).then(function (b) {
console.log(b);
}).catch(function (z) {
console.log(z);
});

axios

Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。axios 地址

  • 从浏览器创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

使用说明中文文档

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
//get请求-----------------------基本使用
axios.get("https://www.ghxi.com/wp-json/wp/v2/posts")
.then(function (a) {
console.log("数据在a对象中的data对象内");
console.log(a);
console.log(a.data);
return a.data;
})
.then(function (b) {
console.log(b);
})
.catch(function (z) {
console.log(z);
});

//post请求-----------------------基本使用
axios.post("https://www.ghxi.com/wp-json/wp/v2/posts", {
//传参写在这里
name: "zs",
age: 18
})
.then(function (a) {
console.log("数据在a对象中的data对象内");
console.log(a);
console.log(a.data);
return a.data;
})
.then(function (b) {
console.log(b);
})
.catch(function (z) {
console.log(z);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//配置全局的默认值
axios.defaults.timeout = 1000; //全局请求超时时间默认2秒
axios.defaults.baseURL = 'https://www.ghxi.com'; //全局请求默认根地址,以后直接写相对地址

axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';


axios.get("/wp-json/wp/v2/posts")
.then(function (a) {
console.log("数据在a对象中的data对象内");
console.log(a);
console.log(a.data);
return a.data;
})
.then(function (b) {
console.log(b);
})
.catch(function (z) {
console.log(z);
});

Symbol

Symbol是es6中新增的一种数据类型,被划分到了基本数据类型中

  • 基本数据类型:字符串、数值、布尔、undefined、null、Symbol
  • 引用数据类型:Object

作用:用来表示一个独一无二的值,无法被覆盖掉。最大的用法是用来定义对象的唯一属性名。

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
let name = Symbol("name"); //name仅仅是一个标记,方便我们知道是哪个Symbol,没有任何含义
let say = Symbol("say");
let obj = {
//如果想使用变量作为对象属性的名称,那么必须加上[]
[name]: "zs",
[say]: function () {
console.log("hello");
},
age: 18,
talk: function () {
console.log("talk");
}
}
obj.name = "ww"; //新增一个name属性
console.log(obj.age); //输出 18
console.log(obj[name]); //输出 zs

//【1.做类型转换的时候不能转换成数值】
console.log(String(name)); //输出 Symbol(name)
console.log(Boolean(name)); //输出 true
console.log(Number(name)); //报错

//【2.不能做任何运算】
console.log(name + 123); //报错
console.log(name + "abc"); //报错

//【3.Symbol生成的值作为属性或方法名称时,一定要保存下来,否则后续无法使用】
let obj = {
[Symbol("name")]:"ls"
}
console.log(Symbol("name"));//拿不到我们想要的 ls
console.log(obj[Symbol("name")]);//也拿不到我们想要的 ls

//【4.for循环无法遍历出Symbol的属性和方法】
//可以用下面这个,把对象传给它,它把对象中所有的属性和方法以数组的形式返回给我们
Object.getOwnPropertySymbols(obj)

Canvas

Canvs是H5新增的一个标签,可以通过js在这个标签上绘制各种图案。

  • <canvas>有默认的宽高,宽300px,高150px
  • 不要在css中设置宽高,那样是拉伸或者缩放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//1.先创建一个canvas标签
document.body.appendChild(document.createElement("canvas"));

//2.通过js拿到canvas标签
let myCanvas = document.querySelector("canvas");

//3.从canvas标签中获取到绘图工具
let myCtx = myCanvas.getContext("2d");

//4.通过绘图工具在canvas标签上绘制图形
myCtx.moveTo(50, 50) //设置路径的起点
myCtx.lineTo(200, 50)
myCtx.lineTo(250, 80)
myCtx.stroke(); //告诉canvas将这些点连接起来

线条相关属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//线条高度
myCtx.lineWidth = 30;
//线条颜色
myCtx.strokeStyle = "#567";
//线条两端样式 round圆形线帽 square正方形线帽 butt默认平直
myCtx.lineCap = "round";
//round圆角 bevel斜角(切片) miter默认尖角
myCtx.lineJoin = "round";

//重新开启一个路径并重新设置样式
myCtx.beginPath();
//终点连接到起点闭合
myCtx.closePath();

//填充闭合区域(默认黑色)
myCtx.fill();
//填充闭合区域 设置填充颜色
myCtx.fillStyle = "blue";

//绘制一条虚线
myCtx.setLineDash([5,20]);//5代表第一段(线条长度),20代表第二段间隔距离

多根线条要重新开启一个路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
myCtx.moveTo(50, 50);
myCtx.lineTo(100, 50);
myCtx.lineWidth = 30;
myCtx.strokeStyle = "red";
myCtx.stroke();

myCtx.beginPath(); //重新开启一个路径并重新设置样式
myCtx.moveTo(100, 100);
myCtx.lineTo(200, 100);
myCtx.lineWidth = 10;
myCtx.strokeStyle = "blue";
myCtx.stroke();

//默认情况下不会自动从最后一个点连接到起点
//可以在最后一个点后加上 xxx.closePath();