本文主要介绍JS异步的实现原理和回调的相关信息。通过示例代码详细介绍,对您的学习或工作有一定的参考价值。有需要的朋友下面和边肖一起学习。
一、JS异步的实现原理
我们知道JavaScript是单线程的,而浏览器是多线程的。单线程执行任务需要逐个排队。如果一个任务需要很长时间执行(像ajax,需要很长时间),会直接导致没有响应,后面的任务一直在等待执行。这是需要异步的时候。
要理解异步,首先我们要知道浏览器有三个基本的常驻线程:JS引擎线程、事件触发线程和GUI渲染线程。
其中,JS引擎线程和事件触发线程构成了一个事件循环机制,而GUI渲染线程和JS引擎是互斥的。JS引擎执行时,GUI线程会被挂起,GUI更新会保存在一个队列中,JS引擎空闲时,会立即执行。
我们从它的事件循环机制来分析:
JS引擎线程分为同步和异步任务:
1.同步任务全部由主线程执行,形成一个执行栈。
2.当有异步任务时,交给异步进程(WebAPIs):它包括事件触发线程或定时器线程,形成任务队列。
3.当执行堆栈中的所有任务都被处理并且主线程空闲时,任务将从任务队列中提取出来并在执行堆栈中执行。
一般来说,JavaScript除了主线程之外还有一个任务队列。任务队列存储需要异步执行的内容。主线程执行后,会循环扫描任务队列中的任务,直到队列为空。
喷漆解决方案:
如图所示,小明灿不能一直玩DNF游戏,因为他的学习需要很长时间。如果他没有完成,就把学习放在异步任务队列里,等游戏(主线程)完成后再学习(任务队列)。期间妈妈添加了学习事件(DOM events),小明每完成一个学习任务就看其他任务(循环扫描)直到最后完成。
下面是另一个例子(浏览器刷新并持续点击按钮):
让我的数据=空
//ajax请求
函数ajax() {
//腾讯新冠肺炎实时数据接口,仅供学习。
axios . get( https://API . inews . QQ . com/news QA/v1/query/inner/publish/modules/list?modules=chinaDayList,chinaDayAddList,nowConfirmStatis,provinces compare’)。然后(data={
console . log(“Ajax成功返回”);
myData=data.data
console . log(my data);
})。catch(错误={
Console.log(ajax返回失败);
})
}
console . log(my data);
ajax()
setTimeout(()={
console . log( timer );
}, 2000);
console . log(my data);
const BTN=document . query selector( button )
btn.onclick=()={
console . log(“clicked”);
}
空
空
Ajax成功返回。
目标
点击。
计时器
点击。
如您所见,控制台首先在主线程中同步执行,而主线程外的任务队列存储异步执行的内容。在这里,setTimeout、ajax和DOM事件按照任务队列(循环扫描队列)的顺序执行。
为什么要循环扫描呢?
从点击事件可以看出,当用户交互时(点击事件、滚动事件、窗口大小改变事件等。),事件循环中会有新的事件加入任务队列,然后等待执行,所以需要循环扫描。
二、JS异步中的回调由于异步是在最后一个任务队列中执行的,所以我们的许多逻辑很难实现。这时候就需要处理这个异步逻辑了,最常见的方式就是回调3354。
回调函数:简单来说,当函数B在函数A中作为参数传递时,函数B就是函数A执行的回调函数,回调有两种类型:嵌套回调和链式回调。
下面是回调的一个简单用法:
让我的数据=空
console . log(my data);
setTimeout(()={
console . log( timer );
}, 2000);
const BTN=document . query selector( button )
btn.onclick=()={
console . log(“clicked”);
}
Let=张三
函数hr(回调){
setTimeout(()={
Console.log(`我是$ { name } `);
回调();
}, 2001);
}
console . log(my data);
函数gj() {
Console.log(`${name}你好,我是李四,认识一下`);
}
人力资源(gj)
空
空
点击。
计时器
我是张三
你好,张。我是李四。来见我。
点击。
显然,当我们的函数需要数据时,我们使用回调,这是异步回调。
虽然回调是解决异步的常用方法,但伴随而来的是JS日益复杂的需求。异步需要越来越多的回调实现逻辑。异步混乱和回调的过度嵌套和缩进使得代码难以解释和维护,导致“回调地狱”。
让我们看一个例子:
const verifyUser=function(用户名、密码、回调){
dataBase.verifyUser(用户名,密码,(错误,用户信息)={
如果(错误){
回调(错误)
}否则{
dataBase.getRoles(用户名,(错误,角色)={
如果(错误){
回调(错误)
}否则{
dataBase.logAccess(用户名,(错误)={
如果(错误){
回调(错误);
}否则{
回调(空、用户信息、角色);
}
})
}
})
}
})
};
大部分人光是看到上面的代码就感觉脑子都要结冰了。如果一个项目中有上百个这样的代码块,过一段时间,我相信连写它的人都会头疼。来到自己的项目就像来到了地狱。
最重要的是,同时,回调存在信任问题。他把执行控制权交给第三方(比如ajax)。为了解决信任问题,必须在程序中编写各种逻辑来解决回调导致的信任问题。
打电话太早
打完电话。
调用太多,调用太少,无法成功地将所需的参数传递给回调函数,
可能的错误会被忽略。
可以发现,编写特定的逻辑来解决特定的信任问题,其难度已经超过了其本身的应用价值,还会造成代码复杂、可读性差等问题。
综上:回调解决异步存在缺陷:
1)不符合人对任务处理的逻辑思维。
2)回调导致的信任问题。
面对日益明显的回调弊端,ES6更新承诺解决异步问题。下一个是ES6——Promise。
总结关于JS异步执行原理和回调的这篇文章到此为止。关于JS异步执行原理回调的更多信息,请搜索我们之前的文章或者继续浏览下面的相关文章。希望大家以后能多多支持我们!