ajax – 終結篇jsonp,防抖節流

今天是我們最後一天ajax的學習,這次學完總可以去vue了吧,我不信還有什麼攔路石,先不說其他的先看看今天的內容。

1.

首先是同源策略,什麼叫做同源?

如果兩個頁面的協議、域名、端口都相同的話,我們將這兩個頁面為同源。

那麼什麼同源策略呢?

是瀏覽器提供的一個安全功能,如果說兩個頁面不同源,那麼A網站就無法讀取B網站的cookie、localstorage、indexdb等;無法接觸B網站的DOM;無法向B網站發送ajax請求

了解了同源與他相反的就是跨域,也就是上面說的協議。域名、端口只要有一個不滿足那麼他們就是跨域。

瀏覽器對跨域請求的攔截,我們是能夠正常發起對服務器的請求的,服務器也能夠感應到請求並將數據返回回來,但是就在臨近城門的時候,在瀏覽器門口就被一個同源策略的門衛攔截住了,一生之敵。

那麼既然如此如何來實現跨域的請求呢?有兩個方式CORS和JSONP。

cors是w3c標準支持get和post

JSONP

原理:由於瀏覽器同源策略的限制,網頁無法通過ajax請求非同源,但是script這個標籤是不受限制的,所以可以通過src這個屬性請求到非同源的script

實現::自己定義一個回調函數,然後通過另一個script標籤的src屬性來調用服務器和一些參數在這個參數裏面callback=這個函數的名字就是你自己回調函數的名字然後後面跟上你自己的參數

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>

        function fn(data) {
            console.log('調用成功');
            console.log(data);
        }
        
    </script>
    <script src="//www.liulongbin.top:3006/api/jsonp?callback=fn&name=張三&age=29&sex=男"></script>


</body>
</html>

JSONP的缺點就是他只支持get請求

2.

jQuery中的JSONP,具體的格式如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>點擊查看jsonp</button>
    <script src="../day01/lib/jquery.js"></script>
    <script>
        $('button').on('click', () => {
            $.ajax({
            url : '//www.liulongbin.top:3006/api/jsonp?name=張三&age=29&sex=男',
            dataType : 'jsonp',
            jsonpCallback : 'fn',
            success : res => console.log(res)
        })
        })
    </script>
</body>
</html>

在這裏面datatype必須制定,然後url中沒有了callback,因為他會自己隨機生成一個callback,你也可以自己修改,jsonpCallback是修改回調函數名字的,jsonp是修改callback的。

在jq中jsonp的一個運行過程也要知道一下,他其實也是依靠script標籤來實現的,在請求的時候他會動態生成一個script標籤在header,然後請求完成又會移出這個標籤。

3.

這些都學完了就可以看到一個案例,模仿淘寶的搜索關鍵字案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <!-- 導入頁面的基本樣式 -->
    <link rel="stylesheet" href="./css/search.css" />
    <!-- 導入 jQuery -->
    <script src="./lib/jquery.js"></script>
    <!-- 3.1插入template 準備用到模板引擎 -->
    <script src="./lib/template-web.js"></script>
    <!-- 3.2定義ui結構 -->
    <script type="text/html" id="suggestList">
      {{each result}}
        <div class="suggest-item">{{$value[0]}}</div>
      {{/each}}
    </script>
    <style>
      .suggest-list {
        display: none;
        border: 1px solid #ccc;
      }
      .suggest-item {
        padding-left: 5px;
        line-height: 30px;
      }
      .suggest-item:hover {
        cursor: pointer;
        background-color: #eee;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <!-- Logo -->
      <img src="./images/taobao_logo.png" alt="" class="logo" />

      <div class="box">
        <!-- tab 欄 -->
        <div class="tabs">
          <div class="tab-active">寶貝</div>
          <div>店鋪</div>
        </div>
        <!-- 搜索區域(搜索框和搜索按鈕) -->
        <div class="search-box">
          <input type="text" class="ipt" placeholder="請輸入要搜索的內容" /><button class="btnSearch">
            搜索
          </button>
        </div>
        <!-- 3.在搜索框下面添加一個盒子拿來裝關鍵字列表 -->
        <div class="suggest-list">

        </div>
      </div>
    </div>
    <script src="./lib/jquery.js"></script>
    <script src="./lib/index.js"></script>
  </body>
</html>

通過jsonp和前面說到的模板引擎來實現

$(function() {
    // 1.先獲取輸入框的文字
    $('.ipt').on('keyup', function(e) {
        let iptText = $(this).val().trim()
        if (iptText == '') {
            // 4.搜索關鍵詞為空時需要隱藏搜索列表
            return $('.suggest-list').empty().hide()
        } else {
            // 2.1調用獲取關鍵字函數
        getSearchList(iptText)
        }
    })
    // 2.封裝獲取建議列表的函數
    function getSearchList(text) {
        $.ajax({
            url : '//suggest.taobao.com/sug?q='+text+'',
            dataType : 'jsonp',
            success : res => {
                getHtml(res)
            }
        })
    }
    // 3.3調用函數並渲染
    function getHtml(res) {
        if (res.result.length <= 0) {
            return $('.suggest-list').empty().hide()
        } else {
            let htmlStr = template('suggestList', res)
            console.log(htmlStr);
            $('.suggest-list').html(htmlStr).show()
        }
    }
})

4.

防抖

防抖策略就是當一個事件被觸發後,延遲幾秒在執行回調函數,如果在這幾秒內又被觸發了,那麼就會重新計時

主要應用場景在用戶輸入時連續輸入一串字符,可以通過防抖策略只有在輸入完畢過後再去執行查詢的請求這樣可以有效減少請求次數。

具體怎麼來實現需要一個定時器,然後定義防抖函數,這個函數裏面開啟定時器獲取jsonp數據渲染html都在這裏面調用,在用戶鍵盤事件這裡清除定時器,輸入一個清除一個輸入一個清除一個,所以只要輸入的夠快,就達不到進入執行這個定時器的門檻,當你停下輸入正常執行代碼,就會開始執行定時器,去調用去請求去渲染

 

$(function() {
    // 防抖1 定義一個延時器
    var timer = null
    // 防抖2 定義防抖函數
    function debounceSearch(text) {
        timer = setTimeout(() => {
            getSearchList(text)
        }, 500);
    }
    // 1.先獲取輸入框的文字
    $('.ipt').on('keyup', function(e) {
        // 防抖3一進來先清除定時器,按一下清一下
        clearTimeout(timer)
        let iptText = $(this).val().trim()
        if (iptText == '') {
            // 4.搜索關鍵詞為空時需要隱藏搜索列表
            return $('.suggest-list').empty().hide()
        } else {
            // 2.1調用獲取關鍵字函數
        // getSearchList(iptText)
        // 防抖4 調用獲取關鍵字函數由定時器執行相當於等你輸完了在執行
        debounceSearch(iptText)
        }
    })
    // 2.封裝獲取建議列表的函數
    function getSearchList(text) {
        $.ajax({
            url : '//suggest.taobao.com/sug?q='+text+'',
            dataType : 'jsonp',
            success : res => {
                getHtml(res)
            }
        })
    }
    // 3.3調用函數並渲染
    function getHtml(res) {
        if (res.result.length <= 0) {
            return $('.suggest-list').empty().hide()
        } else {
            let htmlStr = template('suggestList', res)
            console.log(htmlStr);
            $('.suggest-list').html(htmlStr).show()
        }
    }
})

緩存搜索

就是當我們輸入一個數據的時候又添加一個關鍵字,然後刪了有輸入第一個關鍵字這個時候請求了三次,其中第一次和第三次是重複的,怎麼解決

先定義一個全局的緩存對象,將搜索結果緩存到緩存對象中,優先從緩存中獲取數據.

$(function() {
    // 防抖1 定義一個延時器
    var timer = null
    // 防抖2 定義防抖函數
    function debounceSearch(text) {
        timer = setTimeout(() => {
            getSearchList(text)
        }, 500);
    }
    // 緩存1 定義一個全局空對象
    var resObj = {}
    // 1.先獲取輸入框的文字
    $('.ipt').on('keyup', function(e) {
        // 防抖3一進來先清除定時器,按一下清一下
        clearTimeout(timer)
        let iptText = $(this).val().trim()
        if (iptText == '') {
            // 4.搜索關鍵詞為空時需要隱藏搜索列表
            return $('.suggest-list').empty().hide()
        } else {
            // 緩存3 當我們輸入值得時候就去判斷一下有沒有對象里有沒有該值如果有那直接渲染就是不用再去請求數據
            if (resObj[iptText]) {
                getHtml(resObj[iptText])
            } else {
                // 2.1調用獲取關鍵字函數
        // getSearchList(iptText)
        // 防抖4 調用獲取關鍵字函數由定時器執行相當於等你輸完了在執行
        debounceSearch(iptText)
            }
            
        }
    })
    // 2.封裝獲取建議列表的函數
    function getSearchList(text) {
        $.ajax({
            url : '//suggest.taobao.com/sug?q='+text+'',
            dataType : 'jsonp',
            success : res => {
                console.log(res);
                getHtml(res)
            }
        })
    }
    // 3.3調用函數並渲染
    function getHtml(res) {
        if (res.result.length <= 0) {
            return $('.suggest-list').empty().hide()
        } else {
            let htmlStr = template('suggestList', res)
            // console.log(htmlStr);
            $('.suggest-list').html(htmlStr).show()
            // 緩存2 一切獲取數據輸入完畢在這裡獲取輸入的最終值保存進對象里
            resObj[$('.ipt').val().trim()] = res
        }
    }
})

5.

節流

節流策略就是可以減少一段時間事件的觸發頻率,通過一個節流閥達到本不需要這麼高的觸發率,讓資源空出來

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,body {
            margin: 0;
            padding: 0;
        }
        img {
            position: absolute;
        }
    </style>
</head>
<body>
    <img src="./angel.gif" alt="">
    
    <script>
        /* 普通版
        var img = document.querySelector('img')
        document.onmousemove = function(e) {
            // console.log(11);
            img.style.left = e.pageX + 'px'
            img.style.top = e.pageY + 'px'
        } */
        // 節流版
        var img = document.querySelector('img')
        var timer = null
        document.onmousemove = function(e) {
            // console.log(11);
            if (timer) {
                return
            } else {
                timer = setTimeout(function() {
                    img.style.left = e.pageX + 'px'
                    img.style.top = e.pageY + 'px'
                    timer = null
                },16)
            }
            console.log(11);
        }
    </script>
</body>
</html>

 

Tags: