标梵信息讲解JS异步编程

一.前导内容

       在谈及具体的异步编程前,我们还需要知道何为同步编程,何为异步编程,这两者工作可是有着天差地别。
1.1 何为同步?何为异步?

       那让我来举个栗子吧:假如你需要去做两件事,分别是去煮饭,听一首歌,那么,煮完饭再去听歌的执行流程是同步编程流程。而先煮饭,在煮饭的过程中去听歌的执行流程则是异步编程流程。


1.2 Javascript为什么是单线程
  JS原本的任务就是负责浏览器和用户之间的交互功能,因为JS要操作DOM,所以必须是单线程的,如果你是JS的话,请你想想如果有多个线程同时操作同一个DOM,想必你会抓狂的吧。正因为如此,所以排队等待时间未免太过漫长,所以才有了我们现在口中的JS异步编程的方案。


二.异步编程的核心与方法


2.1 如何实现异步编程?异步编程的核心是什么?
       实现异步编程的方案有很多,例如:回调函数、promise对象,事件监听、发布/订阅等等方案,但万变不离其中,所有异步编程的核心就是回调函数。下面我来举例具体说明一下什么是回调函数:

       假如在煮好饭后要把听歌的耳机放到耳机架上,那么就要把这个事告诉你对象,那异步流程就变成了——你先煮饭,然后告诉你对象等你听完歌需要把耳机放到耳机架上,然后你再去听歌。在这个流程中,把耳机放回耳机架是回调函数,也就是在任务完成后你需要执行的操作,你就是异步操作的调用者,你对象就是异步操作的执行者,总结起来就是——由调用者定义,交给执行者执行的函数,就是回调函数。


2.2 回调地狱问题如何解决?
       说起回调地狱,想必很多小伙伴并不陌生,这个问题也困扰着当时初学JS的我,想当初可是被这个问题折磨了一段时间。接下来就由我给大家说说回调地狱,具体来说回调地狱就是,当你执行DOM事件时,比如在页面上点击链接、回车等操作,浏览器都会悄悄地向服务端发送很多个http请求,携带后台可识别的参数,等待服务器返回数据,这个过程是异步回调的,当很多功能环环依赖时,代码会一层一层的嵌套起来,看起来十分庞大且恶心.

     正是因为回调地狱不利于阅读,同时也不利于维护,所以前辈们为了解决这一问题,在很多方面做出了努力,这个时候我要跟大家分享一个JS异步编程的一个核心要点——promise,下面请用心分析我所说的内容:

(一)何为promise?

      promise是一个构造函数,返回一个promise对象。一个promise指的是一个可能会在未来的某个时间点产生一个单一值的对象。我这里有一个很好的说法可以描述一下promise的机制:

       好比你去汉堡店买汉堡包吃,你已经付好了钱,但是却被告知汉堡包已经售空,而店员为了解决你的问题,给了你一张汉堡兑换券,这张券不会过期,她让你明天再来拿券兑换汉堡包。虽然你的券可以换到汉堡包,但是你也不能确定你明天来时是否有汉堡可以兑换,但可以确定的是,你一定能在未来的某一天,兑换到这个汉堡包。

(二)promise自身的三种状态 (状态改变后就不会再变化)

        (1)fulfilled:成功

        (2)rejected:失败

        (3)pending:等待

   (三)promise的用法

        promise给定了一些原型方法来进行状态处理

1.promise.prototype.then :

        promise对象通过内部resolve函数完成状态的pending ->fulfilled。之后promise将保留这个状态。可以通过then去处理状态。例:pm.then( (val) =>{console.log(val); } )

处理rejected状态,then方法可接收两个函数


new Promise(function(resolve,reject){

    setTimeout(() =>{
    
        reject(new Error('err'))

    },2000).then(null,(error) =>{

            console.log(error);

          })

})

2.promise.prototype.catch:

      用来做错误统一处理,这样的链式调用中我们只需要用then来处理fulfilled状态,在链的末尾加上catch来统一处理错误。

new Promise((resolve,reject) =>{

  setTimeout(() =>{

    resolve = 100;

  },2000).then(result =>{

    return result * num;

    return result / 2;}).catch(err =>{

      console.log(err);

    })

})

3.promise.prototype.finally():

       这个API放在结尾,这时候你们肯定会好奇这是为什么呢?因为它不管前面的promise变为什么,它都会执行里面的回调函数。

new Promise((resolve,reject) =>{

  setTimeout(() =>{

    resolve = 100;

  },2000).then(result =>{

    return result * num;

    return result / 2;}).catch(err =>{

      console.log(err);

      console.log('complete')

    })

})

4.promise.all

Promise.all([A,B]).then(resA,resB) =>{

  //do something

}

5.promise链式调用

       promise对象的then方法会返回一个权限的promise对象

后面的then方法就是为了上一个then返回的promise注册回调

前面的then方法中回调函数的返回值会作为后面then方法回调的参数

如果回调返回的是Promise,后面的then方法的回调会等待它的结束。


2.3 EventlLoop的执行顺序
        EventLoop被称作事件轮询,也称为事件循环,而EventLoop的作用只有一个:监听调用栈和消息队列,一旦调用栈清空,EventLoop就会从消息队列中取出第一个回调函数,压入栈中执行它。

       而就我个人的观点来看,我是这么理解它的:代码从上到下执行,如果遇到微任务就放到微任务队列中,遇到宏任务就放到宏任务队列中,所有代码被执行栈执行完后,先去微任务列表中执行任务,待解决所有微任务后,再去宏任务队列解决所有宏任务。

注意:
1.每当执行完当前宏任务时,都会返回微任务列表看是否有微任务需要执行,若存在微任务则先执行微任务,若没有微任务存在,则执行剩下的宏任务。

2.微任务不需要到队列队尾进行排队处理。

       今天的分享就到这啦,这里是一条从艺术行业初入前端的小咸鱼,欢迎大家提出宝贵的建议,并一起讨论前端的技术知识,希望大家都能在不久的将来成为一名前端老鸟。

本文编辑:济南网站建设公司

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值