需求与研究目的
最近在项目中遇到了这样的问题;进行循环几千次的时候,渲染一个模型;由于模型渲染的比较缓慢,所以模型渲染函数是进行异步调用的;而且是异步里嵌套异步,这就导致了业务流程异常繁琐.所以在这里,想探究总结下前端对异步操作的理解.
什么是异步
我们在日常开发中,常碰到的异步操作如下:
1 ajax服务请求,包括请求什么图片啊,数据啊…
2 常见的一些回调啊,promise类的
理解:
个人对异步的理解还停留在表现;具体的说思维逻辑就是:
在前端开发中,我们的代码都是一行一行的按照顺序往下执行;如果突然,在某处卡死了,造成卡死的原因有很多;那么,我们整个程序就崩了;换句话说,当我们在某处请求个超大资源的时候,比如耗时1分钟,那么这1分钟,我们的程序啥都做不了,造成了资源浪费;这个时候,我们希望,在请求的同时,代码继续向下执行,等请求完了,在对请求的结果进行逻辑处理,所以就产生了异步;
一个异步的情景
这里例句一个例子,在网上,查找了很多异步的例子,但是感觉大都是cp工程师的粘贴复制,很少有自己的见解;所以这里我自己想了一个情景:
A,B两个人,A给了B一百元买一瓶水,这瓶水3元,那么B要找零97元,
找零97元是一个很耗时的过程,毕竟要数钱嘛;在数钱的过程中,A已经很口渴了,
他就直接去拿水了,所以A拿水的结果,是与B是否把钱找零给A没有关系的;这个过程就是一个异步过程;
1 按照正常的逻辑
function A_给钱(){
console.log("A给了100元钱给B");
}
function A_拿水(){
console.log("A去拿水喝");
}
function B_找零钱(){
console.log("B找给A 97元");
}
A_给钱();
B_找零钱();
A_拿水();
2 但是现实中,我们一般等不到A找钱
function A_给钱(){
console.log("A给了100元钱给B");
}
function A_拿水(){
console.log("A去拿水喝");
}
function B_找零钱(){
console.log("B找给A 97元");
}
A_给钱();
A_拿水();
B_找零钱();
3 在2中的例子,一般是现实情况;但是在仔细想想,一般来说,真正的情景应该是这样的:A先给钱,去拿水,然后B刚好数完钱给A;所以这里有个前置条件,就是A给了钱,才能拿水(不要钻牛角尖,说什么能先拿水在给钱)
function A_给钱(callback){
console.log("A给了100元钱给B");
callback();
}
function A_拿水(){
console.log("A去拿水喝");
}
function B_找零钱(){
console.log("B找给A 97元");
}
A_给钱(B_找零钱);
A_拿水();
我们看到,利用回调函数,B找钱是需要A给钱这个条件的;我们进一步还原情景,我们知道,找钱是需要时间的
4 根据上述推理,我们在找钱的时候给一个延迟时间
function A_给钱(callback){
console.log("A给了100元钱给B");
callback();
}
function A_拿水(){
console.log("A去拿水喝");
}
function B_找零钱(){
setTimeout(()=>{
console.log("B找给A 97元");
},3000)
}
A_给钱(B_找零钱);
A_拿水();
从上面的例子中,我们能收获些什么呢?
1 settimeout是异步的
2 回调函数通常用来处理异步过程
3 抽象出回调的异步模型(常用语实战中)
function A(callback){
//做些什么事情,但是很耗时间
callback();
}
function B(){
//这里执行的业务逻辑需要A的结果
}
A(B)
可能小伙伴只看抽象的还不能很理解,我具象化下:
我们假设,A同学很聪明,B同学很笨;这时,B同学被老师点名算1到10的和,B向A小声求救,A算出来后,告诉了B,B回答了老师的问题
function A(callback){
//做些什么事情,但是很耗时间,这里比如我计算1+2+3+....10
setTimeout(()=>{
var count=0;
for(var i=0;i<11;i++){
count+=i;
}
callback(count);
},5000)
}
function B(data){
//这里执行的业务逻辑需要A的结果
console.log("老师,我算出来了,结果是:",data);
}
A(B)
console.log("C同学在抠脚")
从结果,你有什么启发呢?C同学在抠脚竟然先执行了;这说明了什么?说明浏览器没有等到A(B)运行完再去往下运行.这就是异步;
带着问题来学习
情景大概是这样的,就是在一个for循环中,循环几百次吧,然后循环的Array对象是后台ajax服务返回的,然后每循环一次,要做很多业务操作,然后在调用一个异步渲染过程;最后渲染的数据总是出错;(关键是错都不报,直接死掉,排查很困难,上千行代码…),所以这里我抽象一个模型出来:
非常经典的模型
for(var i=0;i<10;i++){
setTimeout(()=>{
console.log(i);
},1000)
}
不出意外,输出10个10,为什么呢?我想基本人人都懂吧…因为1秒后,循环早就都循环完毕了,最后i等于10;
解决办法:
1 在es6中,我们用let,可以限定作用域,解决(本质原理是什么?我也忘记了…)
for(let i=0;i<10;i++){
setTimeout(()=>{
console.log(i);
},1000)
}
2 使用变量替代
for(var i=0;i<10;i++){
let k=i;
setTimeout(()=>{
console.log(k);
},1000)
}
差不多解决办法就是这些吧;
当然网上还有一些对函数的异步操作,像什么搞观察者模式啊,promise啊,其实都差不多;当然我脑洞大开,不是有个aysnc await嘛,心想能不能等变异步为同步啊,跟ajax差不多,哈哈;
aynsc await学习
说到aynsc awati,不得不说promise,他们都是为了解决异步编程而提出的概念,可以推荐大家看一篇博文
https://www.cnblogs.com/CandyManPing/p/9384104.html
感觉写的还可以.这里promise就不多说了,主要说下aynsc await
这里有几点需要时刻放在脑子里:
1 aynsc await 的提出是用来解决异步编程的
2 他们是用来异步函数中的,不能随便拿来用
推理过程:
首先,我们有一个异步函数
//这是一个异步函数...应该问题不大
function test() {
setTimeout(() => {
return "6";
}, 3000)
}
然后我们写个函数对其执行
function test1() {
let n = test()
console.log(n)
}
test1() //undefined
这里结果是未定义,不做过多说明,你问我为啥?3秒内test()函数没执行,n肯定是没有值的
那么我们希望n拿到值后再去输出,怎么办?
1 首先我们考虑用promise去解决
function test() {
return new Promise((rs, rj) => {
setTimeout(() => {
rs("6")
}, 3000)
})
}
function test1() {
let n = test()
console.log(n)
n.then((data) => {
console.log(data)
})
}
test1()
2 我们在考虑用asyncawait去解决
其实1中的解决例子不是很好,我们更期望加个promise能解决问题,但是我们看到,我们其实也改变了test1中的逻辑
那么我们先来看下async
async function test1() {
return "nihao";
}
let p=test1();
console.log(p);
其实async返回的是一个promise啊
好了,发现了一个比较通俗易懂的讲解网站,推荐给大家,我就不写了
https://www.cnblogs.com/yuanyingke/p/10280681.html