一.回调地狱

在谈到回调地狱发生的情况和解决办法,需要先了解ajax请求

先列出服务器提供的数据接口:
app.get('/data1', (req, res) => {
  res.send('hi')
})
app.get('/data2', (req, res) => {
  res.send('hello')
})
app.get('/data3', (req, res) => {
  res.send('nihao')
})
 
// 启动监听
app.listen(3000, () => {
  console.log('running...')
})

 

原生ajax请求步骤

let xhr = new XMLHttpRequest();
xhr.open('get','url')
xhr.send(null);
xhr.onreadystatechange = function(){
  if(xhr.readyState ===4 && xhr.status ===200)
  {
     let ret = xhr.responseText;
     console.log(ret) 
  }  
}

 

函数封装

上面有data1,data2,data3,三次请求,那么就需要写三个ajax,这时就会想到用函数来封装

function queryData(path,callback){
   let xhr = new XMLHttpRequest();
   xhr.open('get','url'+path)
   xhr.send(null); 
   xhr.onreadystatechange = function(){      if(xhr.readyState===4 && xhr.status ===200)
      {
           let ret = xhr.responseText;
           callback(ret)
      }  
   }
}//调用queryData('data1',function(ret){
    console.log(ret)
})

 

如何形成的回调地狱

如果想按顺序获取接口'data1','data2','data3' 中的数据,就会进行下面的操作

queryData('data1',function(ret){
   console.log(ret)  //按顺序第一个输出:hi
   queryData('data2',function(ret){
      console.log(ret)  //第二个输出 hello   queryData('data3',function(ret){
          console.log(ret)  //第三个输出:你好       })
   })
})

如果这里有100个,1000个,甚至更多的请求呢,那真是一场灾难

 

promise方式

为了改造上面的回调函数问题,诞生了promise.promise其实就是一种语法糖(代码形式发生改变,但是功能不变)  

 

function queryData(path) {  return new Promise(function(resolve, reject) {// 需要在这里处理异步任务var xhr = new XMLHttpRequest();
    xhr.open('get','http://localhost:3000/' + path);
    xhr.send(null);
    xhr.onreadystatechange = function() {      // 该函数何时触发?xhr.readyState状态发生变化时  if(xhr.readyState != 4) return;      if(xhr.readyState == 4 && xhr.status == 200) {// 获取后台数据var ret = xhr.responseText;// 成功的情况        resolve(ret);
      } else {// 失败的情况reject('服务器错误');
      }
    }
  })
}

分析

queryData('data1')
  .then(ret=>{
    console.log(ret)  // 顺序输出第一个结果为:hi// 如果在then方法中没有返回Promise实例对象,那么下一个then由默认产生的Promise实例对象调用  })
  .then(ret=>{
    console.log('-------------------' + ret)  // 顺序输出第二个结果为:----------------------undefined// 如果在then中显式地返回一个具体数据,那么下一个then可以获取该数据return 456;
  })
    .then(ret=>{
    console.log('-------------------' + ret)  // 顺序输出第三个结果为:----------------------456
  })

promist对象除了.then方法外,还有两个方法可以通过,调用,其中finally是ES&中新增的方法

.catch(ret=>{  // 发生错误时触发
  console.log('error')
})
.finally(ret=>{  // 无论结果成功还是失败都触发:一般用于释放一些资源
  console.log('finally')
})

 

async和await 进行解决

function queryData(path) {  return new Promise(function(resolve, reject) {// 需要在这里处理异步任务var xhr = new XMLHttpRequest();
    xhr.open('get','http://localhost:3000/' + path);
    xhr.send(null);
    xhr.onreadystatechange = function() {      // 当readyState值不为0的时候直接返回  if(xhr.readyState != 4) return;      if(xhr.readyState == 4 && xhr.status == 200) {// 获取后台数据var ret = xhr.responseText;// 成功的情况        resolve(ret);
      } else {// 失败的情况reject('服务器错误');
      }
    }
  })
} 
async function getAllData() {  // await执行流程是顺序执行
  let ret1 = await queryData('data1');
  let ret2 = await queryData('data2');
  let ret3 = await queryData('data3');
  console.log(ret1)
  console.log(ret2)
  console.log(ret3)
}
getAllData();

需要注意一点:async函数的返回值是Promise实例对象

async function getAllData() {  // await执行流程是顺序执行
  let ret1 = await queryData('data1');  return 'hello';
}var ret = getAllData();
console.log(ret)  // 这里输出一个promise对象,并且resolve的数据为helloret.then(res=>{
  console.log(res)  // 这里输出结果为:hello})

 

以上内容来自:https://www.cnblogs.com/belongs-to-qinghua/p/11161140.html

 

结合promise,做一个小案例,模拟一个对话页面,输入文字,通过接口,获取机器人的对话,同时将对话转为语音放出来

<script>      const baseUrl = "http://www.liulongbin.top:3006";
      window.onload = function () {
        document
          .querySelector("#btnSend")
          .addEventListener("click", function () {
            let str = document.querySelector("#ipt").value.trim();if (!str) {
              alert("信息不能为空");              return;
            }
            appendContent(str, "right");
            document.querySelector("#ipt").value = "";//获取机器人信息            getJiQiRXX(str)
              .then((res) => {
                appendContent(res.data.info.text);return getJiQiYY(res.data.info.text);
              })
              .then((res) => {// console.log("语音内容", res);document.querySelector("audio").src = res.voiceUrl;
              });
          });
      };

      function getJiQiRXX(spoken) {return new Promise((resolve, reject) => {          //请求机器人信息  let xhr = new XMLHttpRequest();
          xhr.open("get", baseUrl + "/api/robot?spoken=" + spoken);
          xhr.send(null);
          xhr.onreadystatechange = function () {if (xhr.readyState === 4) {              if (xhr.status === 200) {
                let data = JSON.parse(xhr.responseText);
                resolve(data);// console.log(xhr.responseText);  } else {
                reject("请求失败,请稍后再试");
              }
            }
          };
        });
      }

      function getJiQiYY(text) {return new Promise((resolve, reject) => {
          let xhr = new XMLHttpRequest();
          xhr.open("get", baseUrl + "/api/synthesize?text=" + text);
          xhr.send(null);
          xhr.onreadystatechange = function () {if (xhr.readyState === 4) {              if (xhr.status === 200) {
                let data = JSON.parse(xhr.responseText);
                resolve(data);
              } else {
                reject("请求失败,请稍后再试");
              }
            }
          };
        });
      }      // function scrollChange() {}      function appendContent(str, who) {
        let li = document.createElement("li");
        li.className = who === "right" ? "right_word" : "left_word";
        li.innerHTML = `<img src="img/${  who === "right" ? "person02.png" : "person01.png"}" /> <span>${str}</span>`;document.querySelector("#talk_list").appendChild(li);//滚动document.querySelector("#talk_list").scrollTop = document.querySelector(          "#talk_list").scrollHeight;
      }</script>

 

结合async await,做一个小案例,模拟一个对话页面,输入文字,通过接口,获取机器人的对话,同时将对话转为语音放出来

const baseUrl = "http://www.liulongbin.top:3006";
      window.onload = function () {
        document
          .querySelector("#btnSend")
          .addEventListener("click", function () {
            let str = document.querySelector("#ipt").value.trim();
            if (!str) {
              alert("信息不能为空");
              return;
            }
            appendContent(str, "right");
            document.querySelector("#ipt").value = "";
            // //获取机器人信息
            // getJiQiRXX(str)
            //   .then((res) => {
            //     appendContent(res.data.info.text);
            //     //获取语音
            //     return getJiQiYY(res.data.info.text);
            //   })
            //   .then((res) => {
            //     // console.log("语音内容", res);
            //     document.querySelector("audio").src = res.voiceUrl;
            //   });
            getAllData(str);
          });
      };

      async function getAllData(spoken) {
        //获取机器人信息
        let res1 = await getJiQiRXX(spoken);
        appendContent(res1.data.info.text);
        //获取语音信息
        let res2 = await getJiQiYY(res1.data.info.text);
        document.querySelector("audio").src = res2.voiceUrl;
      }

      function getJiQiRXX(spoken) {
        return new Promise((resolve, reject) => {
          //请求机器人信息
          let xhr = new XMLHttpRequest();
          xhr.open("get", baseUrl + "/api/robot?spoken=" + spoken);
          xhr.send(null);
          xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
              if (xhr.status === 200) {
                let data = JSON.parse(xhr.responseText);
                resolve(data);
                // console.log(xhr.responseText);
              } else {
                reject("请求失败,请稍后再试");
              }
            }
          };
        });
      }

      function getJiQiYY(text) {
        return new Promise((resolve, reject) => {
          let xhr = new XMLHttpRequest();
          xhr.open("get", baseUrl + "/api/synthesize?text=" + text);
          xhr.send(null);
          xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
              if (xhr.status === 200) {
                let data = JSON.parse(xhr.responseText);
                resolve(data);
              } else {
                reject("请求失败,请稍后再试");
              }
            }
          };
        });
      }

      // function scrollChange() {}
      function appendContent(str, who) {
        let li = document.createElement("li");
        li.className = who === "right" ? "right_word" : "left_word";
        li.innerHTML = `<img src="img/${
          who === "right" ? "person02.png" : "person01.png"
        }" /> <span>${str}</span>`;
        document.querySelector("#talk_list").appendChild(li);
        //滚动
        document.querySelector("#talk_list").scrollTop = document.querySelector(
          "#talk_list"
        ).scrollHeight;
      }