likes
comments
collection
share

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字

作者站长头像
站长
· 阅读数 9

回调函数

回调函数就是一个被作为参数传递的函数

说的通俗点就是,当一个函数A作为参数,被传入另一个函数B中,并且它不会立刻执行,而是只有当满足一定条件后函数A才可以执行,那么像A这种函数就称为回调函数。

像定时器和ajax中就存在有回调函数。

//定义一个函数
var A = function (){
    console.log('我是回调函数A');
}
//把函数当作参数传递进另一个函数
setTimeout(A,3000);

同步任务和异步任务

同步任务

如下面的代码:

console.log('最先执行我');
console.log('然后执行我');
console.log('最后执行我');

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 上面代码就是一个同步任务的示例,每个console语句就是一个“任务”,同步任务在主线程上排队执行只有当前一个任务执行完毕,下一个任务才能执行(也可以理解为就是按代码的先后顺序执行)。

异步任务

异步任务与同步任务相对应,异步任务不进入主线程,而是进入异步队列中,前一个任务是否执行完毕并不影响下一个任务的执行

setTimeout(function(){
    console.log('我虽然在代码的位置靠前,但是我后执行');
},3000);
console.log('我虽然在代码最后后面,但是我比上面那个console先执行');

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 像这种不会阻塞后面任务执行的任务,就叫做异步任务。

上面的两个示例,我们可以推论出一个结果:如果代码中存在异步任务,那我们就不能保证代码会按照顺序执行

那么如果我们杠一下,非要让存在异步任务的代码按顺序执行呢?这就是下面讲的回调地狱了。

回调地狱

既然是涉及到顺序,那么用我们汉语的语序做例子最容易理解了。比如说有一句话,“大家好,我是,蜻蜓队长”,要用异步的方式正确的输出这句话,就需要像下面这样写:

setTimeout(function(){
    console.log('大家好');
    setTimeout(function(){
        console.log('我是');
        setTimeout(function(){
            console.log('蜻蜓队长');
        },1000);
    },2000);
},3000);

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 像上面这样的代码,在回调函数中嵌套回调函数的情况就叫做回调地狱。 回调地狱是为了实现代码顺序执行而出现的一种操作,虽然这样确实实现了我们的需求,按顺序输出了我们要说的话,但是这样会造成我们的代码可读性非常差,维护起来难死了。

那么有啥办法解决回调地狱呢?就是我们下面的Promise了。

Promise

Promise是js中的一个原生对象(其实是一个构造函数),是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案,其自身有all、reject、resolve这些方法,原型上有then、catch等方法。 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字

Promise构造函数

Promise构造函数接收一个函数A作为参数。 函数A的两个参数是 resolve、reject,函数A的函数体就是我们要处理的异步任务,异步任务执行成功时调用resolve函数返回结果,否则的话就调用reject函数返回结果。

Promise对象

Promise对象的then方法用来接收处理成功时响应的数据,catch方法则用来接收处理失败时响应的数据。

通过在每一次then做完处理后,return一个Promise对象,可以实现Promise的链式编程,进而保证代码的执行顺序。

Promise对象的两个特点

Promise对象的状态不受外界影响。 Promise对象代表一个异步操作,有三种状态:

  1. pending(进行中)
  2. fulfilled(已成功)
  3. rejected(已失败)

只有异步操作的结果可以决定当前的状态是哪一种,其他任何操作都无法改变这个状态。

Promise对象的状态一旦改变就不会再变,任何时候都可以得到这个结果。 Promise对象状态的改变只会有两种可能:

  1. pending -> fulfilled
  2. pending -> rejected

只要这两种状态发生,对象的状态就凝固了,不会再改变了(一直保持这个状态),这时称为 resolved(已定型),如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

上面这个特性也是Promise对象与事件Event不同的地方,事件的特点是,如果你错过了它,再去监听,是得不到结果的

通俗点讲,一个人本来是单身状态,然后状态改变了,变成了已婚状态(这时改变以及发生了),此时你再去查看这个人的状态(添加回调函数),会得到他已婚的结果,而事件则啥也查看不到。

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 使用Promise使得我们的代码看起来整洁了那么一点点,但是也仅仅是一点点,当代码量多起来的时候,比如我要蜻蜓队长唱一首歌,那岂不是满屏的then...then...。

因此,在ES7中,可以使用 async/await 关键字使得我们的代码看起来更像同步代码。

async/await关键字

async关键字

放在声明函数的前面,表示该函数作为一个异步任务,不会阻塞后面函数的执行。

const isSpeak = true;//给不给蜻蜓队长说话

async function Speak(Str){
   if(isSpeak){
       return Str;
   }else{
       throw '不给蜻蜓队长说话';
   }
}
console.log(Speak());

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 从上面的结果可以看出,async关键字声明的函数返回数据时,自动封装为一个Promise对象,所以处理异步任务时和上上面的方式一样,使用then和catch。 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字

await关键字

wait => 等待,当代码执行到 async 函数中的await时,代码就会在此处等待,直到await拿到了promise对象中的resolve的数据,才会继续往下执行,这样保证了代码的执行顺序,并且使得异步代码看起来更像同步代码。

使用方法

  1. await 关键字只能用在 async 声明的函数里面;
  2. await 关键字后面可以直接跟一个Promise实例对象,也可以跟一个表达式(返回一个Promise对象的表达式);
  3. await 关键字不能单独使用;
  4. await 关键字可以直接拿到Promise中 resolve 的数据;

【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 await 关键字是不会处理 Promise对象的 reject(err) 的,比如下面不让蜻蜓队长说话。 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 这个时候就需要用到 try...catch... 来处理了。 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 【JS】回调函数、回调地狱、Promise基本概念、async/await关键字 完结