Promise相關內容(三)——非同步獲取伺服器資料:promise方式解決回撥地獄的問題。通過多個.then使程式碼可讀性更高 & 解決非同步任務的序列執行,保證按順序傳送請求獲取資料

viceen發表於2020-12-03

Promise相關內容(三)——非同步獲取伺服器資料:promise方式解決回撥地獄的問題。通過多個.then使程式碼可讀性更高 & 解決非同步任務的序列執行,保證按順序傳送請求獲取資料

第一種形式:常規寫法-正常

第一步:新建myapi資料夾

第二步:在資料夾myapi裡面新建index.js和pubulic資料夾

第三步:在publice資料夾下新建檔案01.html

內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div>Promise</div>
  <script type="text/javascript">
    /*
      如何獲取非同步的結果
    */
    function queryData () {
      let xhr = new XMLHttpRequest()
      xhr.open('get', 'data')
      xhr.send(null)
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            // 獲取伺服器響應的結果
            let ret = xhr.responseText
            console.log(ret)
          }
        }
      }
    }
    queryData()
    
    </script>
</body>
</html>

第四步:index.js檔案如下:

const express = require('express');
const app = express();

// 啟動靜態資源服務
app.use(express.static('public'))

app.get('/data', (req, res) => {
  let info = {
    username: 'lisi',
    age: 12
  }
  // res.send('Hello World')
  res.json(info)
})

app.listen(3000, () => {
  console.log('running...')
})

第五步:在myapi資料夾下,命令列啟動伺服器

node index.js

第六步:開啟頁面,控制檯驗證獲取資料——22行和伺服器均驗證成功

在這裡插入圖片描述

第二種形式:如果返回值形式驗證,顯示undefined

    function queryData () {
      let xhr = new XMLHttpRequest()
      xhr.open('get', 'data')
      xhr.send(null)
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            // 獲取伺服器響應的結果
            let ret = xhr.responseText
           // console.log(ret)
+          return ret            
          }
        }
      }
    }
-    queryData()
+    let ret = queryData()
+    console.log(ret)  

此時列印ret,顯示為undefined

第三種形式:返回值形式驗證,顯示為null

    /*
      如何獲取非同步的結果
    */
  function queryData () {
    let xhr = new XMLHttpRequest()
    xhr.open('get', 'data')
    xhr.send(null)
 +   let ret = null
     // 回撥函式(定義——由自己定義,由別人/瀏覽器呼叫)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          // 獲取伺服器響應的結果
          // let ret = xhr.responseText
          // console.log(ret)
          // return ret

          ret = xhr.responseText
        }
      }
    }
    return ret   //為null原因:當返回值時,ret此時尚為空
  }
 // 非同步的結果無法通過返回值的方式獲取
 // 必須使用回撥函式的方式獲取
+  let ret = queryData()
+   console.log(ret)  

拿不到結果,顯示為空。列印為顯示為null

第四種形式:回撥函式的方式獲取資料驗證,正常顯示

單層回撥
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div>Promise</div>
  <script type="text/javascript">
    /*
      如何獲取非同步的結果
    */
  function queryData (callback) {
    let xhr = new XMLHttpRequest()
    xhr.open('get', 'data')
    xhr.send(null)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          // 獲取伺服器響應的結果
          let ret = xhr.responseText
          callback(ret)       
        }
      }
    }
   
  }
  // callback(ret)中的ret傳給data
  queryData(function(data) {
    console.log(data)
  })

    </script>
</body>
</html>

開啟頁面,顯示正常(回撥函式,獲取資料)

在這裡插入圖片描述

**變形寫法:**加個路徑,顯示結果沒有變化

注意寫法對比,程式碼如下

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div>Promise</div>
  <script type="text/javascript">
    /*
      如何獲取非同步的結果
    */
+  function queryData (callback,path) {
    let xhr = new XMLHttpRequest()
+    xhr.open('get', path)
    xhr.send(null)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          // 獲取伺服器響應的結果
          let ret = xhr.responseText
          callback(ret)       
        }
      }
    }
   
  }
  // callback(ret)中的ret傳給data
  queryData(function(data) {
    console.log(data)
+  },'data')

    </script>
</body>
</html>

列印data,顯示結果同上

多層回撥,出現回撥地獄,影響效能
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div>Promise</div>
  <script type="text/javascript">
    /*
      如何獲取非同步的結果
    */
  function queryData (callback,path) {
    let xhr = new XMLHttpRequest()
    xhr.open('get', path)
    xhr.send(null)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          // 獲取伺服器響應的結果
          let ret = xhr.responseText
          callback(ret)       
        }
      }
    }
   
  }
  // callback(ret)中的ret傳給data
  // queryData(function(data) {
  //   console.log(data)
  // },'data')
    // 回撥地獄
  queryData(function(data) {
    console.log(data)
    queryData(function(data) {
      console.log(data)
      queryData(function(data) {
        console.log(data)
      }, 'data2')
    }, 'data1')
  }, 'data')

    </script>
</body>
</html>

多層回撥,出現回撥地獄,可讀性不高,不推薦

在這裡插入圖片描述

為了解決上述問題(非同步獲取資料和多層巢狀出現的回撥地獄),就誕生了Promise

解決非同步任務的序列執行,按順序執行任務,保證第一個非同步任務的結果拿到後,再發請求進行第二個非同步任務,依次類推;採用promise方式,不用巢狀,改為橫向的水平關係(多個.then),程式碼的可讀性更高,解決回撥地獄的問題

單層資料獲取
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div>Promise</div>
  <script type="text/javascript">
    /*
      如何獲取非同步的結果
    */
    function queryData (path) {
    return new Promise(function(resolve, reject) {
      // 處理非同步任務
      let xhr = new XMLHttpRequest()
      xhr.open('get', path)
      xhr.send(null)
      // 回撥函式(由自己定義,由別人呼叫)
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            // 獲取伺服器響應的結果
            let ret = xhr.responseText
            resolve(ret)
          }
        }
      }
    })
  }

  queryData('data')
    .then(ret => {
      console.log(ret)
    })
    </script>
</body>
</html>

顯示結果正常

在這裡插入圖片描述

多層資料時,也正常
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div>Promise</div>
  <script type="text/javascript">
    /*
      如何獲取非同步的結果
    */
    function queryData (path) {
    return new Promise(function(resolve, reject) {
      // 處理非同步任務
      let xhr = new XMLHttpRequest()
      xhr.open('get', path)
      xhr.send(null)
      // 回撥函式(由自己定義,由別人呼叫)
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            // 獲取伺服器響應的結果
            let ret = xhr.responseText
            resolve(ret)
          }
        }
      }
    })
  }

  queryData('data')
    .then(ret => {
      console.log(ret)
      return queryData('data1')
    })
    .then(ret=>{
      console.log(ret)
      return queryData('data2')
    })
    .then(ret=>{
      console.log(ret)
    })
    </script>
</body>
</html>

顯示正常

在這裡插入圖片描述

相關文章