欢迎来到DIVCSS5查找CSS资料与学习DIV CSS布局技术!
导读
 
首先,要知道JavaScript是一门单线程的语言,要搞明白其为何会设计成单线程,要先来说一下JavaScript的最初应用场景。
 
其次,在单线程语言中如何处理多线程的任务。
 
再次,同步和异步的流程以及如何理解异步。
 
然后,在解决复杂的逻辑业务时,出现了什么样的问题。
 
再然后,怎样解决这一问题。
 
=> Promise/.then(),async/await,
 
最后谈谈微任务及宏任务
 
JavaScript最初的应用场景
 
最初,JavaScript的设计是作为浏览器脚本语言实现用户的交互,而为了避免多线程给我们带来很多不必要的麻烦,比如说:一个线程在删除一个节点,而另一个线程在修改这个节点,这时我们应该以哪一条线程为主呢?
 
因此,设计者将其设计成单线程的语言。
 
在H5中规定了JS可以拥有多个子线程,但是子线程仍然是依托于主线程的,且不能够操作节点。
 
为什么要使用多线程
 
单线程的缺点:
 
单线程有一个“致命”的缺点,就是会造成阻塞;
 
因为是单线程,所以在程序运行时是按照先进先出的原则来进行任务处理的,也正是因如此,在主线程遇到了耗时操作后,其后的任务就进入到了等待的状态。如果此时CPU是被占用的,也没什么,但是如果这个耗时任务是一个不占CPU的操作,举个栗子:向服务端请求数据。这个时候CPU出入空闲状态但是程序并没有执行结束,这就形成了阻塞。
 
启发:
 
在进行耗时操作且影响代码正常运行时,我们可以先不管这个操作,将其挂起。先处理后面的任务,等到主线程清空时,再来执行这个任务。于是出现了同步任务和异步任务。
 
同步和异步及程序运行流程
 
关于这一块内容,笔者建议从整体来看,将这一块中的内容结合起来读,可能会更好理解
 
我们可以将同步任务理解为在主线程中执行的任务,异步任务理解为在子线程执行。
 
同步任务和异步任务的执行过程:
 
同步任务正常运行,没有特殊情况会一直执行完毕;
 
当主线程运行到异步任务时,会安排一个子线程去运行异步任务,当异步任务运行结束后,向任务队列发送一个事件。表示该异步任务可以进入主线程执行了。
 
当不考虑下面讲的微任务和宏任务时,我们的程序运行时,会先执行同步任务,执行到异步任务后,将其发送到子线程中运行,运行结束会向任务队列发送一个事件。同步任务执行完毕即主线程清空后,主线程会向任务队列询问,是否有接收到事件,如果没有,那么主线程会一直询问,这个过程称为event loop;如果有,就执行这个事件。直到程序全部完成。
 
事件
 
在上文我们提到了事件这一概念,可以将事件理解为异步任务返回的一个回调函数,这个回调函数也就是事件会在主线程上运行。异步任务必须有回调函数。
 
拓展:异步函数必须return一个Promise对象
 
关于事件,阮一峰前辈是这么写的:
 
"任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
 
“回调地狱”
 
在实际开发中,为了实现一些逻辑需求,可能会用到多层回调函数嵌套。这个时候会导致代码的可读性很差。人们称之为“回调地狱”
 
Promise对象
 
代表的是异步操作 最终完成或失败
 
目的:将回调函数的多层嵌套形式,拆解成链式调用的形式。
 
本质:函数返回的对象,在这个对象上绑定回调函数,避免从一开始将回调函数作为参数传入上一层函数。
 
一个Promise必然会处于这几种状态:
 
待定(pending):初始状态,既没有被兑现,也没有被拒绝
 
已兑现(fulfilled):意味着操作成功完成 resolve
 
已拒绝(rejected):意味着操作失败 reject
 
Promise的使用:一般作为函数的返回值
 
const fn = function(){
 
    return new Promise((resolve,reject)=>{
 
        if(ture){
 
            resolve(a);
 
        }else{
 
            reject(b);
 
        }
 
    })
 
}
 
 
fn()
 
    .then((res)=>{有返回值的函数})
 
    .then((res)=>{有返回值的函数})
 
    .then((res)=>{有返回值的函数})
 
    …
 
    .then(res=>{最后的函数})
 
// 如果Promise对象中的请求完成了,那么将resolve的值传给then中的回调函数作为参数执行then方法
 
// 可以附加 .catch()在链式结构的末尾,来捕获错误(reject传回的值),并且之后的then不会执行
 
// 可以在最后加一个 .finally() 来执行清理操作  并且这个方法不管请求成功与否都会执行
 
async/await
 
是Promise的语法糖;让繁琐的then(),和冗长的链式调用可读性变得更长些;
 
具体使用方式:
 
//异步函数1
 
function getData(data){  
 
    return new Promise((reslove)=>{
 
        reslove(data)
 
    })
 
}
 
//异步函数2
 
function sayHello(data){
 
    return new Promise((reslove)=>{
 
        reslove(data)
 
    })
 
}
 
 
//异步函数 
 
async function fn(){
 
     // await相当于。then()    getData()相当于是回调函数
 
    // await必须在async修饰的函数体内使用
 
    const promiseA = await getData('info')
 
    const promiseB = await sayHello(promiseA);
 
    console.log(promiseB)
 
}
 
谈谈微任务和宏任务
 
微任务
 
注意:Promise对象中的代码是同步的,then()方法中的回调函数才是异步的
 
then()中的是微任务
 
宏任务
 
定时器是宏任务
 
代码执行顺序口诀:先同步后异步,先微任务后宏任务
 
总之,同微宏

如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h64349.shtml