解析Promise解决异步回调

137 阅读4分钟

Promise是ES6语法中新增的一个标准内置对象,它代表了一个异步操作的最终完成或者失败,能够把异步操作最终的成功返回值或者失败原因和相应的处理函数关联起来,是异步“回调地狱”的解决方案之一。

1 应用场景

要了解Promise对象,首先要了解这个对象的应用场景,Promise对象主要就是为了解决异步回调地狱问题的,那么什么是回调函数呢?请看下面的一段代码:

// 定义一个函数a
function a(cb) {
  cb()
}
// 定义一个函数b
function b() {
  console.log('我是函数 b')
}
// 在函数a调用的时候,把函数b位置函数a的实参传入
a(b)

此时,函数a和函数a的参数都是一个函数,为了便于区别,我们把作为函数a参数传入的那个函数b叫做函数a的回调函数,我们为什么需要回调函数?

 当我们执行一个异步的行为的时候,我们需要在一个异步行为执行完毕之后做一些事情,那么,我们是没有办法提前预知这个异步行为是什么时候完成的,我们就只能以回调函数的形式来进行,比如我们需要通过ajax请求一个数据,根据ajax返回的结果执行不同的代码,但是我们不知道ajax对象什么时候能获取到返回结果,就需要使用回调函数,看下面的代码:

// 定义data变量用户存储ajax获取到的数据
 let data = null;
 // 执行ajax获取数据的函数
 function getData(){
   let xhr = new XMLHttpRequest();
   xhr.open('GET','/data.json');
   // 监听ajax的onload事件,事件触发的时候就是请求完成的时候
   xhr.onload = function(){
     // 请求完成,ajax获取到的数据赋值给data
     data = xhr.responseText;
   }
   xhr.send(null)
 }

 // ajax成功返回数据以后,根据返回的数据执行的代码
 function showData(){
   document.body.innerHTML = data;
 }


 getData();
 showData();

如果采用上面的调用方式,先调用getData获取数据以后直接调用showData显示数据,那么document.body.innerHTML = null,因为此时data还没有获取到数据,请求时异步的,我们需要在请求完成的时候调用showData才行,也就是像下面这样调用


// 定义data变量用户存储ajax获取到的数据
  let data = null;
  // 执行ajax获取数据的函数
  function getData(cb){
    let xhr = new XMLHttpRequest();
    xhr.open('GET','/data.json');
    // 监听ajax的onload事件,事件触发的时候就是请求完成的时候
    xhr.onload = function(){
      // 请求完成,ajax获取到的数据赋值给data
      data = xhr.responseText;
      // 之后再调用传入的showData函数
      cb();
    }
    xhr.send(null)
  }

  // ajax成功返回数据以后,根据返回的数据执行的代码
  function showData(){
    document.body.innerHTML = data;
  }
  getData(showData);

2 回调地狱

当一个回调函数嵌套一个回调函数的时候,就会出现一个嵌套结构,当嵌套的多了就会出现回调地狱的情况, 比如我们发送三个 ajax 请求,第一个正常发送,第二个请求需要第一个请求的结果中的某一个值作为参数,第三个请求需要第二个请求的结果中的某一个值作为参数


ajax({
   url: '我是第一个请求',
   success (res) {
     // 现在发送第二个请求
     ajax({
       url: '我是第二个请求'data: { a: res.a, b: res.b },
       success (res2) {
         // 进行第三个请求
         ajax({
           url: '我是第三个请求',
           data: { a: res2.a, b: res2.b },
           success (res3) {
               console.log(res3) ;
               // ...
           }
         })
       }
     })
   }
 })

  • 回调地狱,其实就是回调函数嵌套过多导致的,当代码成为这个结构以后,已经没有维护的可能了,所以我们要把代码写的更加的艺术一些。

3 Promise的使用

Promise是一个对象,这个对象有三个状态:

  • 待定(pending):初始状态,既没有成功,也没有失败,表示异步任务正在进行中
  • 成功(fulfilled):异步任务执行完毕,变成成功状态
  • 失败(rejected):异步任务执行完毕,变成失败状态

下面就带大家创建一个Promise对象

let p1 = new Promise(function (resolve, reject) {
    // 此处执行异步的代码
    setTimeout(()=>{
        // 我们可以根据自己的标准在异步任务完成的时候
        // 选择是执行失败的回调函数还是成功的回调函数
        // 第一个形参resolve 表示成功的回调
        resolve('300')
        // 第二个形参reject 表示失败的回调
    },3000)
})

// 定义当p1这个promise对象变成成功状态的时候要执行的回调函数
p1.then((data)=>{
    console.log("我是成功的时候执行的函数")
    console.log("我执行的时候你给我传入的参数",data)
})

// 定义当p1这个promise对象变成失败状态的时候要执行的回调函数
p1.catch((err)=>{
    console.log("我是失败的时候执行的函数")
    console.log("我执行的时候你给我传入的参数",err)
})