0%

Promise 异步

js核心代码在执行过程中,有的代码 代码 会在跳过执行,等待一段时间以后 又会继续执行,打破了从上至下,从左至右的执行顺序, 这种代码我们统称为异步代码

  • 定时器 延时器
  • ajax
  • 事件的监听和执行函数
  • Promise 异步 类

1.基础语法

promise状态:

pending 等待

resolve=== fulfilled 成功

reject rejected 失败

promise 状态只会有一个结果, 状态不可逆, 等待--->成功 等待-->失败

1
2
3
4
5
6
7
8
9
10
11
12
//创建pormise实例对象
let p1 = new Promise(function(resolve,reject){
// resolve:等待一段时间后 成功执行之后的回调函数
// reject: 等待一段时间后 失败执行之后的回调函数
//如果promise 的状态 是不成功 不失败 pending 等待....
resolve() //只要调用了resolve 就表示状态改为成功fulfilled
reject() //只要调用了reject 状态就表示 失败rejected
})




2.promise 解决的问题

回调地狱问题

回调函数 有 回调 里面 还有回调

回调函数嵌套 层级 超过三层,一般就说形成了回调地狱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

const http = {
get(url,callback){
let xhr = new XMLHttpRequest();
xhr.open('get',url);
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
callback(JSON.parse(xhr.responseText))
}
}
},
post(url,data,callback){
let xhr = new XMLHttpRequest();
xhr.open('post',url);
xhr.setReqeustHeader('content-type','application/json')
xhr.send(JSON.stringify(data))
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
callback(JSON.parse(xhr.responseText))
}
}
},
}

3.通过ajax 体验回调地狱 11:15

http.js 实现

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
  
<div class="list">

</div>

<script src="./http.js"></script>
<script>
let listDom = document.querySelector('.list')
let data = [];
// 请求用户的列表
http.get('/list',(res)=>{

data= res.data
//循环数组 拿到id 请求对应的username 更新到data里面

for(let i=0;i<data.length;i++){
http.post('/info',{id:data[i].id},(res1)=>{
data[i].username = res1.data.username
//请求头像
let formData = {id:data[i].id,username: data[i].username}
http.post('/avatar',formData,(res2)=>{
data[i].avatar = res2.data.avatar;

//将最新数据 拼接dom输出到页面
listDom.innerHTML+=`
<div class="item">
<div class="img">
<img src="${data[i].avatar}" alt="">
</div>
<div class="info">
<div class="id">
用户编号:${data[i].id}
</div>
<div class="name">
用户名字:${data[i].username}
</div>
</div>
</div>
`;
})

})
}
})
</script>

3.回调地狱

多个回调函数的嵌套,超过3级 形成回调地狱 【代码的可读性极低】

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
http.get('/list',(res)=>{
data= res.data
//循环数组 拿到id 请求对应的username 更新到data里面
for(let i=0;i<data.length;i++){
http.post('/info',{id:data[i].id},(res1)=>{
data[i].username = res1.data.username
//请求头像
let formData = {id:data[i].id,username: res1.data.username}
http.post('/avatar',formData,(res2)=>{
data[i].avatar = res2.data.avatar;

//将最新数据 拼接dom输出到页面
listDom.innerHTML+=`
<div class="item">
<div class="img">
<img src="${data[i].avatar}" alt="">
</div>
<div class="info">
<div class="id">
用户编号:${data[i].id}
</div>
<div class="name">
用户名字:${data[i].username}
</div>
</div>
</div>
`;
})
})
}
})

3.promise 解决回调地狱问题

三个:

pending 等待

fufailled resolve 成功

rejected reject 失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1s 之后 通过promise 返回  这个数字   默认pending
// 偶数:是偶数 promise 成功状态
// 奇数:是奇数 promise 失败状态
let num =100
new Promise(function(resolve,reject){
setTimeout(()=>{
if(num%2 ==0){
resolve('是偶数')
}else{
reject('是奇数')
}
},1000)
}).then(function(res){
console.log(res);
}).catch(function(err){
console.log(err);
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//1s 之后 通过promise 返回  这个数字   默认pending
// 偶数:是偶数 promise 成功状态
// 奇数:是奇数 promise 失败状态
let num =101
let p = new Promise(function(resolve,reject){
setTimeout(()=>{
if(num%2 ==0){
resolve('是偶数')
}else{
reject('是奇数')
}
},1000)
})

//成功后自动执行then 调用了resolve 自动走 then
p.then(function(res){
console.log(res);
})

//失败后自动执行catch 调用了reject 自动走 catch
p.catch(function(err){
console.log(err);

})

4.promise 的then 的链式调用

promise 的 then链式调用 可以解决ajax 的回调地狱

1
2
p.then(res=>{}).then(res1=>{}).then(res2=>{})
//链式then的调用共计3次 ===> 一共调用了 三次 reslove ===> 三个promise
  • ajax 请求的三次接口
1
2
3
4
5
6
7
8
9
10
11
let data = {};
http.get('/list',res=>{
data = res.data;
http.post('/info',{id:res.data.id},res1=>{
http.post('/avatar',{id:res1.data.id,username:res1.data.username},res2=>{
data.username = res2.data.username;
data.avatar = res2.data.avatar;
console.log(data);
})
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
new Promise((resolve,reject)=>{
http.get('/list',res=>{
data = res.data;
resolve(res)
})
}).then(res=>{
return new Promise((resolve,reject)=>{
http.post('/info',{id:res.data.id},res1=>{
resolve(res1)
})
})
}).then(res1=>{
return new Promise((resolve,reject)=>{
http.post('/avatar',{id:res1.data.id,username:res1.data.username},res2=>{
resolve(res2)
})
})
}).then(res2=>{
console.log(res2);
data.avatar = res2.data.avatar;
data.username = res2.data.username
})

5.简化代码 ,提炼公共部分代码 形成代码的封装

复写axios.js

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
const base_url = 'http://8.137.157.16:9004'
const http = {
get(url){
let p = new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('get',base_url+url);
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
return p;
},
post(url,data){
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('post',base_url+url);
xhr.setRequestHeader('content-type','application/json')
xhr.send(JSON.stringify(data))
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
},
}
window.http = http;
1
2
3
4
5
6
7
8
http.get('/list')
.then(res => {
return http.post('/info', { id: res.data.id })
}).then(res1 => {
return http.post('/avatar', { id: res1.data.id, username: res1.data.username })
}).then(res2 => {
console.log(res2);
})

6.axios 的使用与原理

promise+ajax(XMLHttpReqeust)

  • 找axios的中文网
  • 下载axios.js bootcdn 下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 <script src="./axios.js"></script>
<script>
let data = {};

// 统一服务器地址
axios.defaults.baseURL = 'http://8.137.157.16:9004';

axios.get('/list')
.then(res => {
console.log(res);
return axios.post('/info', { id: res.data.data.id })
}).then(res1 => {
return axios.post('/avatar', { id: res1.data.data.id, username: res1.data.data.username })
}).then(res2 => {
console.log(res2.data);
})

  • http.js 封装
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
let base_url = 'http://8.137.157.16:9004'
const http = (obj)=>{
let {method,url,data,responseType} = obj;
if(method=='get'){
return http.get(url)
}
if(method=='post'){
let type = responseType==0?'application/json':'application/x-www-form-urlencoded'
return http.post(url,data,type)
}
}
http.get = (url)=>{
let p = new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();

xhr.open('get',base_url+url);
xhr.send()
xhr.onreadystatechange = function(){

if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
return p;
}
http.post = (url,data,responseType='application/json')=>{
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('post',base_url+url);
xhr.setRequestHeader('content-type',responseType)
xhr.send(JSON.stringify(data))
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}
}
})
}
window.http = http;

7. 浏览器事件循环机制 event loop

同步 异步的深入研究

代码执行顺序

定时器 延时器

ajax 事件

promise

1.promise 是异步吗?

promise 本身不是异步, promise.then 方法是异步

2.同步和 异步问题

先执行所有的同步 再 执行异步

3.浏览器事件循环机制

代码执行顺序:

遵循 从上至下 从左至右 依次执行。

异步代码: 宏任务(定时器 延时器 ajax 事件) 微任务 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
console.log(1);



new Promise((resolve,reject)=>{
console.log(3);

console.log(5);
resolve()
}).then(_=>{
setTimeout(()=>{
console.log(4);
},0)
console.log(6);

})
console.log(7);


setTimeout(()=>{
console.log(2);

},0)

// 1 3 5 7 6 2 4

面试题:

1.你对回调地狱的理解?

2.如何解决回调地狱?

3.event loop 浏览器事件循环机制 (关于同步异步代码的执行顺序)?

4.promise 是异步还是同步?

5.宏任务和微任务的区别 分别有哪些?

async await promise 内置方法 all race

屏幕兼容处理与移动端兼容|可视化大屏

  • 自适应 与 响应式布局的区别 –通过js实现
  • 关于移动端开发的兼容方案
  • 关于大屏幕开发的兼容方案

1.自适应 与响应式布局

自适应: 通过css方式,能够达到:不同设备显示相同效果

​ 优点: 只需要写一套css 缺点: 网页中文字只能缩小到12px 继续缩小也没有效果了,盒子内容溢出 导致页面混乱。 现在谷歌支持小于12px, 文字太小,用户看不到

响应式 :通过 css 监听或控制页面 根据 不同设备显示不同效果

​ 优点:不同设备 的 样式显示比较好看 缺点:需要多套css样式

2.移动端兼容方法

2.1 流式布局 -【自适应】

所有盒子的宽 高间距 尽量使用 百分比 文字大小都用百分比

1
2
3
4
5
6
7
8
9
.box{
width:100%;
height:100%; //父盒子先用具体高度
}
.box1{
width:50%;
height:40%;
fontsize:100%;
}

2.2 自适应方案 2: rem em rpx

动态html body 的fontsize 实现rem单位自动 缩放

根据屏幕宽高 动态计算 html body 标签的字体大小,所有盒子 高 宽 字体大小 间距 都是用rem 单位

使用场景:

屏幕大小变动不大,推荐:只做 移动端兼容 ,或 只做pc兼容,

同时兼容横屏 竖屏 不推荐这种方式

  • 自适应方案3: rpx

原理: 1px ==2rpx 基准屏幕宽度为375px

​ 1px ==1rpx 当前屏幕为750px

1
2
3
4
.box{
width:10rpx; //如果是375屏幕 5px 屏幕:750 ===>10px
hegiht:10rpx;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const resize =()=>{
console.log('resize,屏幕发生了改变');
// 获取当前的屏幕宽高
let width = document.documentElement.clientWidth;
// 屏幕基准值: 你当前屏幕 相对之前写死的值 是放大了 还是缩小了
// 800px ===> 10px 推算: 1000px===>12px 公式: 当前屏幕宽度/基准宽度 *盒子原宽度
// 1920px 屏幕基准值 ==> 72px*72px 10000px ==> 10000/1920 *72 ==375px *375px

let fs = width/375*10
console.log(fs);
document.documentElement.style.fontSize = fs + 'px'
}
resize()


window.addEventListener('resize',resize)

rem:相对页面根节点的 fontsize 的 相对单位

​ 例:【谷歌浏览器 html生效】 html body fontsize ==20px 1rem ==20px

em: 1个字体单位 父盒子的fontsize 大小

​ 例如: 父盒子的fontsize = 30px 1em ==30px

rpx :就是微信小程序官方 提供的 rem 的进阶版

问题: 流式布局 解决了 盒子宽高 间距 根据屏幕大小自动变化的问题,但没有解决字体大小变化的问题

  • 通过 设置 html ,body标签的fontsize 实现rem的字体的相对单位
  • 因为html body 固定的fangsize 导致 rem 也变成了固定值
  • html body的 fontsize 跟随 屏幕的宽高 变化 而进行变化【必须使用js 监听屏幕宽高改变】

2.3 方案3 : 利用淘宝的 flexible.js 实现方案2的效果

2.4 方案4: 基于 前端工程化项目的插件 postcss-px2rem 实现方案2的效果

1
2
3
https://blog.csdn.net/qq_54527592/article/details/120249040
vite 配置postcss
taro vite 配置postcss
  • 项目安装 postcss-px2rem
1
pnpm install  postcss-px2rem  amfe-flexible 
  • 配置vite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// vite.config.js 或 vite.config.ts
import { defineConfig } from 'vite';
import px2rem from 'postcss-px2rem';

export default defineConfig({
css: {
postcss: {
plugins: [
px2rem({
// 配置 px2rem 的选项
rootValue: 37.5, // 设计稿宽度 / 10,例如设计稿为 375px 则设置为 37.5
unitPrecision: 5, // px 转换成 rem 的小数位数
propList: ['*'], // 需要进行转换的属性,'*' 表示全部属性
selectorBlackList: [], // 需要忽略选择器的转换的正则表达式
replace: true, // 是否替换原有的 px
mediaQuery: false, // 是否允许在媒体查询中转换 px
minPixelValue: 0 // 小于或等于 minPixelValue 的 px 不进行转换
})
]
}
}
});
  • main.jsx
1
2
3
4
5
6
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import 'amfe-flexible' //导入 插件 根据插件 实现 根据屏幕动态更改 html的fontsize
import './index.css'
import App from './App.jsx'

3.响应式布局

不同的设备 显示不同的效果(存在多套的css )

3.1 媒体查询 –css解决方案-【掌握 记住语法 常见屏幕高宽】

优点:所有兼容处理方案 中 最完美的,可以按照 不同的屏幕宽度 加载不同的css样式

缺点: 一套样式需要重复写多次

通过css 实现判断 当前的屏幕 需要使用 那一套 样式

常见屏幕高宽:

移动端不要超过

iphone 5 320

ihone 6-8 375

ihone678s XR 414

iphone 12 390

iphone 14 430

ipad 768 700-800

pc: 1080 1920

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
/* 写一套默认样式 */
.menu{
width: 100%;
height: 60px;
border-bottom: 1px solid #ccc;
display: flex;
justify-content: space-between;
}
.icon{
width: 50px;
height: 60px;
text-align: center;
line-height: 60px;
display: none;
}
.title{
width: 200px;
height: 60px;
line-height: 60px;
}
.list{
display: flex;
}
.item{
width: 80px;
height: 60px;
line-height: 60px;

}

/* 监听当前屏幕 的宽度 属性哪个范围 加载对应的css,对应css可以覆盖默认的样式 */
/* 写的越多套 不同屏幕的样式 */
/* 移动端 320以上 */
@media screen and (min-width:320px) {
.list{
display: none;
}
.icon{
display: block;
}
}

/* 平板 */
@media screen and (min-width:700px) and (max-width:900px) {
.list{
display: block;
}
.icon{
background: #f44;
display: block;
}
}


/* pc */

@media screen and (min-width:900px){

}


案例:

pc上 盒子的高宽 400*450 背景色 为 #f44

平板 盒子高宽 200*260 背景色位 blue

iphone6/7/8 盒子高宽 120*140 背景色 skyblue 外边距 20px

iphone 12-14 盒子高宽 140*170 背景色为白色 外边框为1px的green 线条 内边距为10px

3.2 Ui框架实现响应式布局的方案

  • elemnt plus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<el-row :gutter="10">
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">
<div class="grid-content ep-bg-purple" />
</el-col>
<el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">
<div class="grid-content ep-bg-purple-light" />
</el-col>
<el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">
<div class="grid-content ep-bg-purple" />
</el-col>
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">
<div class="grid-content ep-bg-purple-light" />
</el-col>
</el-row>
  • antd
1
2
3
4
5
6
7
8
9
10
11
<Row>
<Col xs={2} sm={4} md={6} lg={8} xl={10}>
Col
</Col>
<Col xs={20} sm={16} md={12} lg={8} xl={4}>
Col
</Col>
<Col xs={2} sm={4} md={6} lg={8} xl={10}>
Col
</Col>
</Row>

4.特殊处理: 专门做大屏的 整个缩放

transform:scale(缩放倍数)

假设 不清楚 甲方的 大屏幕 到底是多大

按照设计图进行 px 直接写,写完样式之后 进行 自适应 transform 缩放布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 基准值  1920*1080   x y  ==1
//通过js 获取屏幕的宽高 当前宽/1920 = 2

const resize = ()=>{
console.log('111');

// 获取屏幕宽度
let width = document.documentElement.clientWidth;
let h = document.documentElement.clientHeight;
let x = width/1920;
let y = h/1080
// 可以根据屏幕缩放的比例 进行整个页面的缩放
document.documentElement.style.transform = `scale(${x},${y})`
// 缩放之后需要调整缩放的位置 有偏移量
document.documentElement.style.transformOrigin = '50% 50%'

}
resize()
window.addEventListener('resize',resize)

5.datav 可视化大屏框架-【推荐】

官网地址:http://datav-react.jiaminghi.com/

面试题

  • 浏览器的字体大小 默认字体大小:16px 最小字体大小:12px-【如果小于12px 必须使用缩放 transform:scale zoom, 现在浏览器已经支持 最小字体可以小于12px】

  • 自适应的方案:

    • 根据屏幕宽高 动态计算 html body 标签的字体大小,所有盒子 高 宽 字体大小 间距 都是用rem 单位