1.回调地狱
回调地狱
+ 回调函数内书写回调函数
+ 代码的阅读性和可维护性极低
分析:
+ 因为你的封装是按照 回调函数 的模式进行封装了
+ 调用的时候, 就必须按照 回调函数 的模式进行调用
+ 解决: 从根本上解决问题, 不在按照 回调函数 的模式进行封装了
+ ES6 提供了一个新的 异步封装 方案, 叫做 Promise
思考:
+ 今后封装 异步操作 的时候
=> 回调函数 形式
=> Promise 形式
+ 如果你是按照 回调函数 形式封装
=> 必须按照 回调函数 形式调用
=> 就会出现回调地狱
+ 如果你是按照 Promise 形式封装
=> 必须按照 Promise 的语法调用
需求:
1. 发送请求, 请求 /test/first 地址
2. 发送请求, 请求 /test/second 地址, 要求, 在第一个请求结束以后在请求
3. 发送请求, 请求 /test/third 地址, 要求, 在第二个请求结束以后在请求
例:
ajax({
url: 'http://localhost:8888/test/first',
success (res) {
console.log('第一次的请求结果 : ', res)
// 这个位置的代码执行, 一定是第一个成功了
// 应该在这里发送第二个请求
ajax({
url: 'http://localhost:8888/test/second',
dataType: 'json',
success (res) {
console.log('第一次的请求结果 : ', res)
ajax({
url: 'http://localhost:8888/test/third',
data: { name: 'Jack', age: 18 },
dataType: 'json',
success (res) {
console.log('第一次的请求结果 : ', res)
}
})
}
})
}
})
2.Promise语法
Promise 语法
+ Promise 承诺
+ 一个 Promise 只有三个状态
=> peading 持续
=> fulfilled 成功
=> rejected 失败
+ 状态转换只有两种
=> 持续 -> 成功
=> 持续 -> 失败
基础语法:
+ const p = new Promise(function () {
// 书写你的异步代码
// 根据代码逻辑让本次 Promise 转换状态到成功或者失败
})
=> 私人: 对你做出一个承诺
+ p.then(function () {
// 当前这个 Promise 状态有 持续转换到成功 的时候会执行
})
+ p.catch(function () {
// 当前这个 Promise 状态由 持续转换到失败 的时候会执行
})
例:
//Promise基础应用 // a b
const p = new Promise(function (resolve, reject) {
// 第一个参数: 是一个函数数据类型, 当调用的时候, 会被本次 Promise 状态由持续转换为成功
// 第二个参数: 是一个函数数据类型, 当调用的时候, 会把本次 Promise 状态由持续转换为失败
// 书写一段异步代码
const n = Math.floor(Math.random() * 3001 + 2000)
setTimeout(() => {
if (n >= 3500) {
// 表示成功
resolve(n) //resolve调用下面的 p.then这个函数
} else {
// 表示失败
reject('我错了') //reject调用下面的 p.catch这个函数
}
}, n)
})
1.注册一个成功的回调
p.then(function (n) {
console.log('成功了', n)
})
2.注册一个失败的回调
p.catch(function (err) {
console.log('失败了', err)
})
3.可以直接链式编程书写(基础写法的改进) //给个承诺 成功走他 失败走他 类似三元表达式
new Promise(function (resolve, reject) { //整体是个承诺
const n = Math.floor(Math.random() * 3001 + 2000)
setTimeout(() => {
if (n >= 3500) {
resolve(n)
} else {
reject('我错了')
}
}, n)
})
.then(function (n) {
console.log('成功了', n)
})
.catch(function (err) {
console.log('失败了', err)
})
4.封装
4.1 只要我能拿到一个 Promise 对象, 就可以注册 .then 和 .catch
function fn() {
const p = new Promise(function (resolve, reject) {
const n = Math.floor(Math.random() * 3001 + 2000)
setTimeout(() => {
if (n >= 3500) {
resolve(n)
} else {
reject('我错了')
}
}, n)
})
// 把这个 Promsie 对象当做返回值
return p
}
让这个承诺开始执行
res 接受的是, fn 函数内的返回值, 也就是 fn 函数内的 p
实际上就是一个 Promsie 对象
//1.写法一
const res = fn()
res.then(function (n) {
console.log('成功了', n)
})
res.catch(function (err) {
console.log('失败了', err)
})
//2.写法二(用这个)
fn()
.then(function (n) {
console.log('成功了', n)
})
.catch(function (err) {
console.log('失败了', err)
})
4.2 尝试 ajax 的二次封装
pAjax({ url: 'http://localhost:8888/test/first', dataType: 'json' })
.then(res => console.log('请求成功 : ', res))
.catch(err => console.log('请求失败 : ', err))
4.3 尝试三个需求
/*
需求:
1. 发送请求, 请求 /test/first 地址
2. 发送请求, 请求 /test/second 地址, 要求, 在第一个请求结束以后在请求
3. 发送请求, 请求 /test/third 地址, 要求, 在第二个请求结束以后在请求
Promise 有一个特殊的调用方式 !!!!!!!链式
+ 可以链式 then 书写
+ 当你前一个 then 里面 return 一个 Promise 对象的时候
+ 可以在前一个 then 后面再写一个 then
*/
pAjax({ url: 'http://localhost:8888/test/first' })
.then(res => {
console.log('第一个请求成功 : ', res)
return pAjax({ url: 'http://localhost:8888/test/second', dataType: 'json' })
})
.then(res => {
console.log('第二个请求成功 : ', res)
return pAjax({ url: 'http://localhost:8888/test/third', data: { name: 'Jack', age: 18 }, dataType: 'json' })
})
.then(res => {
console.log('第三个请求成功 : ', res)
})
3.async 和 await 关键字
async 和 await 关键字
+ 目的: 为了把异步代码写的看起来像同步代码(不会修改异步的本质)
async 关键字
+ 书写在函数的前面
+ 目的:
=> 为了可以再该函数内使用 await 关键字
await 关键字
+ 书写在一个有 async 关键字的函数内
+ await 等待的意思
=> await 后面得到的必须是一个 Promise 对象
+ 目的:
=> 你本该在 then 内接受的结果, 可以直接定义变量接受了
例:
fn()
async function fn() {
// await 关键字会让当前函数内的代码等待, 等到后面这个 Promise 完全完成
// 把结果给到 r1 变量以后, 在继续向后执行代码
const r1 = await pAjax({ url: 'http://localhost:8888/test/first' })
console.log(r1)
// 这里的代码能执行, 说明前一个 Promise 必须完成
const r2 = await pAjax({ url: 'http://localhost:8888/test/second', dataType: 'json' })
console.log(r2)
// 这里的代码能执行, 说明前一个 Promise 必须完成
const r3 = await pAjax({ url: 'http://localhost:8888/test/third', data: { name: 'Jack', age: 18 }, dataType: 'json' })
console.log(r3)
}
进化:
4.宏任务和微任务
1. js 是事件驱动型语言
任何的操作都是事件驱动处理
把每个操作可以理解为一个任务
而任务中分为同步和异步任务
同步任务是指当前任务执行完成后再执行下一个任务 ,会等待当前任务执行完成后,在执行后续
异步任务会将当前任务存放在一个特殊任务列表中,当时间到了,或者事情完成了,调用
这个任务列表中设定的任务执行
2.这些都是异步的(除了下面这些 其他都是同步)
加载图片、文件
与服务器通信
setTimeout setInterval setImmediate(暂时未学) 宏任务
Promise process.nextTick()(暂时未学) 微任务 async函数返回的结果也是Promise
3.同步任务、宏任务、微任务执行顺序(记)
个人语义化: 同步任务先执行 微任务后执行 宏任务最后执行
但是宏任务分层级 宏任务第一层先执行 层层递进
如图:
例:
例子1.-任务顺序
setTimeout(function(){ //宏任务等所有任务需求都完成才执行宏任务
console.log("c"); //3
},1000);
//如果这个时间比同步任务的时间要更快完成,就会等待同步任务全部执行完成后立即执行这个异步任务
var time=Date.now();
console.log("a"); //1
for(var i=0;i<1000000000;i++){
}
console.log("b"); //2
console.log(Date.now()-time); //a b 2580 c
例子2.
console.log(1); //1
setTimeout(function(){ //没写时间一般认为是同步任务的下一个任务
console.log(2); //6
});
console.log(3); //2
new Promise(function(resolve,reject){
console.log(4);//3 //这是同步任务 promise里只有.them和.catch才是异步
resolve();
}).then(function(){
console.log(5)//5 //Promise的then或者catch才是异步任务
});
console.log(6)//4
var time=Date.now();
setTimeout(function(){
console.log(Date.now()-time);
// 当没有设置时间时,下一帧执行这个函数,
})
例子3.
setTimeout(function(){
Promise.resolve().then(function(){
console.log(1); //1 宏任务里套微任务 他快
})
});
Promise.resolve().then(function(){
setTimeout(function(){
console.log(2); //2 微任务里套宏任务
})
})
如图:
5.Cookie
/* 浏览器的本地存储 - cookie
本地存储
+ 利用浏览器帮我们存储一些信息
+ 可以
=> 跨页面通讯
=> 前后端交互
=> 免密登录 直接
+ 有多种
=> cookie
=> localStorage
=> sessionStorage
cookie 的特点(熟读并背诵全文)
1. cookie 是基于域名存储的
=> 哪一个域名存储, 哪一个域名使用
=> 本地文件是不行的
2. cookie 的存储有大小限制
=> 4KB 左右
=> 50 条左右
3. cookie 的存储数据格式
=> 只能是字符串格式的内容
=> 格式: 'key=value; key2=value'
4. cookie 存储是有时效性的
=> 默认是会话级别的时效, 关闭浏览器自动删除
=> 可以手动设置过期时间, 不管是否关闭浏览器, 都会计时 (七天免登陆)
5. 前后端传输
=> 只要 cookie 空间内有内容
=> 在当前页面内发送的所有给后端的信息, 都会自动携带 cookie
6. 前后端操作
=> 前端可以依靠 js 来操作
=> 后端可以依靠任何语言操作
*/
/*
服务器打开页面
+ 页面打开方式有两种
=> 本地打开
-> file://
=> 依赖服务器打开
-> http://
-> https://
-> ...
+ 如何进行服务器打开
=> 暂时下载一个 vscode 的插件 live server
=> 打开页面的时候, 你的编辑器文件目录内必须要有文件夹
=> 右键, open with live server
-> 快捷键 alt + l 和 alt + o
=> vscode 就会在你的电脑上启动一个临时服务器, 支持该页面的打开
*/
/*
cookie 的设置
+ 语法: document.cookie = 'key=value'
+ 一次只能设置一条
cookie 设置的时候加上修饰信息
+ 语法: document.cookie = 'key=value; 修饰信息'
+ 修饰一个过期时间
=> document.cookie = 'key=value;expires=时间对象'
*/
// 1.设置一条 cookie
document.cookie = 'a=100'
document.cookie = 'a=200' //他的设置不同名 第二次设置就是修改
document.cookie = 'b=200'
// 2.设置一条带有过期时间的 cookie
/*
当你给 cookie 设置时效的时候, 不管你给他的是什么时间节点
他都当做世界标准时间来使用
你设置的是 15:35, cookie 就把 15:35 当做世界标准时间来设置
本条 cookie 会在世界标准时间 15:35 分过期
当前终端时间 23:35 分过期
*/
var time = new Date('2022-4-21 7:38:30')
document.cookie = 'a=100;expires=' + time
/*
3.设置一条 30s 以后过期的 cookie
+ 需要拿到一个当前时间节点的时间对象
+ 向前调整时间 8 小时
+ 再向后调整事件 30s
*/
//这就是设置一个cookie
var time = new Date()
time.setTime(time.getTime() - 1000 * 60 * 60 * 8 + 1000 * 30)
document.cookie = 'a=100;expires=' + time
4.封装一个设置 cookie 的方法
// 参数:
// key 你设置的 cookie 的名字
// value 你设置的 cookie 的值
// expires 你设置的过期时间, 选填, 没写, 默认按照会话级别(浏览器关了就没了)
function setCookie(key, value, expires) {
// 判断 expores 是否存在
if (expires) {
// 调整一个时间对象
var time = new Date()
time.setTime(time.getTime() - 1000 * 60 * 60 * 8 + 1000 * expires)
}
// 直接设置 cookie
document.cookie = `${ key }=${ value }; expires=${ time }`
}
// 你将来使用的时候
// 需要设置一个 30s 以后过期的 cookie
setCookie('a', 100, 30)
setCookie('b', 200)
// 删除 cookie
function delCookie(key) {
setCookie(key, '', -1)
}
/*
获取 cookie
+ 语法: document.cookie
+ 得到: 完整的 cookie 字符串
*/
function getCookie() {
// 1. 拿到 cookie 字符串
var cookie = document.cookie
console.log(cookie)
// 2. 准备一个空对象
var obj = {}
// 3. 按照 ';'
var tmp = cookie.split('; ')
// 4. 遍历 tmp
tmp.forEach(function (item) {
var t = item.split('=')
obj[t[0]] = t[1]
})
// 5. 返回 obj
return obj
}
var res = getCookie()
console.log(res)
5.1 Cookie补充
1.cookie在向服务器发起请求时,会自动携带发送到服务器,而服务器在
处理完成后也可以写入到用户的计算机内。也就是cookie会随着网络请求往返于用户端和服务端之间
因为具备服务器写入和自动携带性,所以一般用于作为自动登录的存储
用于记录用户行为和信息,以到达广告的精准投放
2、cookie存储的数据不能过大,大小仅能在5K
3、cookie存储可以按照时间达到存储时长的要求 expires=格林尼治时间字符串
4、cookie有路径关系和域名关系,跨域是不能相互访问,双击文件打开是无法使用cookie,
父级路径是无法访问子级路径中cookie,子级路径是可以访问父级
路径中cookie,可以通过设置Path=路径 存储当前cookie
5、cookie是不安全,明文存储,所以所有存储信息需要加密
6.webStorage
/*
面试的坑:
解释以下 cookie localStorage sessionStorage session 的区别
*/
/*
浏览器的本地存储 - storage
+ localStorage 和 sessionStorage
+ 浏览器本地的存储 (除了可以存储变量外,还可以存储所有文本数据)
+ 特点:
=> 只能存储字符串类型
=> 如果你需要存储的是 对象或者数组 相关的内容
=> 转换为 json 格式存储
storage 和 cookie 的区别
1. 存储位置
+ cookie 以域名为基础存储(没有域名不能读写)
+ storage 以域名为基础存储(没有域名可以读写)
2. 存储大小
+ cookie 4KB 左右
+ storage 20MB 左右
3. 时效性
=> cookie 默认会话级别时效, 可以手动设置过期时间
=> localStorage 必然是永久存储
=> sessionStorage 必然是会话存储
4. 前后端交互
=> cookie 会自动携带
=> storage 不会自动携带
5. 前后端操作
=> cookie 前后端都可以操作
=> storage 只能前端操作 js
session
+ 是一个服务端的存储空间
*/
/*
localStorage 的操作 (也不接受重名)
+ JS 提供了完整的 增删改查 语法
增:
+ 语法: window.localStorage.setItem('key', 'value')
查:
+ 语法: window.localStorage.getItem('key')
删:
+ 语法: window.localStorage.removeItem('key')
清空:
+ 语法: window.localStorage.clear()
*/
var obj = { name: 'Jack', age: 18, gender: '男' }
var arr = [
{ name: 'Jack', age: 18, gender: '男' },
{ name: 'Rose', age: 20, gender: '女' },
{ name: 'Tom', age: 22, gender: '男' }
]
// 1. 增
window.localStorage.setItem('a', 100) //只能存储字符串类型
window.localStorage.setItem('user_info', JSON.stringify(obj))//如果你需要存储的是 对象或者数组 相关的内容
window.localStorage.setItem('user_list', JSON.stringify(arr))//转换为 json 格式存储
// 2. 查
var res = JSON.parse(window.localStorage.getItem('user_info'))
console.log(res)
// 3. 删
window.localStorage.removeItem('user_list')
// 4. 清空
window.localStorage.clear()
/*
sessionStroage 的基本操作
+ JS 提供了完整的 增删改查 操作方法
增:
+ 语法: window.sessionStorage.setItem('key', 'value')
查:
+ 语法: window.sessionStorage.getItem('key')
删:
+ 语法: window.sessionStorage.removeItem('key')
清空:
+ 语法: window.sessionStorage.clear()
*/
var obj = { name: 'Jack', age: 18, gender: '男' }
var arr = [
{ name: 'Jack', age: 18, gender: '男' },
{ name: 'Rose', age: 20, gender: '女' },
{ name: 'Tom', age: 22, gender: '男' }
]
// 1. 增
window.sessionStorage.setItem('a', '100')
window.sessionStorage.setItem('user_info', JSON.stringify(obj))
window.sessionStorage.setItem('user_list', JSON.stringify(arr))
// 2. 查
var res = window.sessionStorage.getItem('a')
console.log(res)
// 3. 删
window.sessionStorage.removeItem('user_list')
// 4. 清空
window.sessionStorage.clear()