zoukankan      html  css  js  c++  java
  • 异步(二)回调地狱

    一.回调地狱

    在谈到回调地狱发生的情况和解决办法,需要先了解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的数据为hello
    ret.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;
          }
    

      

  • 相关阅读:
    环保
    A股行情记录
    航运
    黑五类
    家电
    妖股
    高校概念股
    科技园区
    壳股
    白底黑字or黑底白字,眼睛更喜欢哪一个?
  • 原文地址:https://www.cnblogs.com/zmztya/p/14295538.html
Copyright © 2011-2022 走看看