美文网首页
前端性能优化实践:Ajax请求优化新体验

前端性能优化实践:Ajax请求优化新体验

作者: 我是云小梦 | 来源:发表于2020-06-18 09:31 被阅读0次

说起来ajax,相信诸位都不会陌生 —— 这可是当下前端最火的技术之一。

ajax请求数据,将数据拿到前端页面上,通过一定手段展示给用户,造成“不必刷新页面”的局部数据刷新。这是ajax最主要的功能。
一直以来使用ajax都是“横冲直撞”:不管三七二十一,调用就完了。拿到数据后也是直接放到页面区域上

——一般来说没有什么问题,直到遇见了分页:一个大数据量重复请求的场景。

于是,我们对ajax的使用做了优化:
(本文所说皆基于“切换分页”场景)


fg

ajax分页缓存

这个可是个“明星人物”。它基于这样一个背景:当你点击某一页时,网站会想后台发一个请求,接收到返回数据后跳过去(局部刷新)。这时,如果没有设置缓存,那么原来页面的数据就不会被浏览器“记住”,当你返回这个页面时浏览器会再一次发送请求,甚至当你中途退出后再进来,又回到原来的下标了。这大大加重了浏览器和服务器的负担!

对如下场景:

<div class="wrap flex_column">
    <div class="content flex_column"></div>
    <div class="page">
        <ul class="flex_row">
            <!-- <li></li> --> <!-- 这里实际是后端动态渲染列表 -->
        </ul>
    </div>
</div>

即是要缓存,我们在获取元素时就要设置【缓存对象】:

var oContent=document.querySelector('.content');
var oPages=document.querySelector('.page ul li');

var cache={};
changePage();   //运行“检查数据”函数

检查数据函数的代码如下:

function changePage(){
    for(let i=0,len=oPages.length;i<len;i++){  //这里实际要换成从后端ajax过来的长度
        if(oPages[i] in cache){
            console.log('已经存在了数据');
            //...
        }else{
            console.log('数据还没有,正在加载中...');
            //...
        }
        console.log(cache);
    }
}

可以看到,我们在函数中先进行判断:当前列表项是否已经在缓存中:如果在缓存中了,那我们就不必再发送ajax请求数据 —— 那样会增加服务器的压力,而是直接从缓存中拿到数据:
在上面代码if中,增加:addDom(cache[i]);

function addDom(result){
    var dataList=result;
    var dataLength=dataList.length;
    var str='';
    for(var i=0;i<dataLength;i++){
        str+=`
            <a href="${dataList[i].url}" class="items flex_row">
                <div class="img">
                    <img src="xxx" alt="" />
                </div>
                <div class="bd">
                    <p class="label">${dataList[i].title}</p>
                </div>
            </a>`
    }
    oContent.innerHTML=str;
}

反之,我们就要发送ajax从服务器拿到数据:
在else中增加代码 goTo(page);

function goTo(page){
    Ajax({
        url:'xxxx',
        method:'GET',
        data:{
            //...
            page
        },
        success:function(res){
            var result=JSON.parse(res);
            var dataList=result.showapi_res_body.newslist;
            //先获取到我们的数据数组
            addDom(dataList);
            cache[page]=dataList;
        }
    });
}

这个思路在“切换分页”这个场景下用的非常多 —— 每次切换时都要将当前页的数据存到缓存中,每次切换时都先去看一下要去的“上一页”或“下一页”的数据是否在缓存中(之前是否切换到此也过),做不同的处理。

fg

使用H5的history改善Ajax列表请求

既然HTML5的众多API都是基于浏览器原生的,那么我们从原生的角度来看一下请求数据加载:
当前在点击“下一页”时,大部分网页都采用了动态请求的方式,避免页面刷新。虽然大家都是ajax,但是从一些小的细节还是可以看出其优劣:比如是否支持浏览器“后退”和“前进”键(左上角的两个按钮)。

数据分页显示,早起的做法是在网址后面加个page的参数:在点击“下一页”时,让网页重定向到page+1的新地址。例如之前新浪的新闻网就是这么做的。但是这个列表并不是页面的主体部分!或者说页面的其他部分也有很多图片等丰富的元素,例如导航slider —— 再使用这样的方式,整个页面会闪烁的很厉害,并且很多资源得重新渲染。
但是话说回来,普通的动态请求不会使网址发生变化。用户点击了下一页,或者点击了第几页,想返回到上一个页面时,可能去点浏览器的返回键,这样就导致了返回的不是原先查看的页面信息,而是上一个网址了,或者想刷新一下,发现回到了第一页。
下面以笔者所做的一个案例进行分析:

var pageIndex=0;
function makePage(pageIndex){
    var request=new XMLHttpRequest();
    request.open("GET","/getBook?page="+pageIndex+"&limit=8",true);
    request.send(null);
    request.onreadystatechange=statechange;
    
    function statechange(){
        if(this.readyState == 4 && this.status == 200){
            var books=JSON.parse(request.responseText);
            renderPage(books);   //渲染数据
        }
    }
}

拿到数据后进行渲染:

function renderPage(books){
    var bookHtml=`<table>`;
    for(let i in books){
        bookHtml+=`<tr><td>${books[i].name}</td><td>${books[i].author}</td></tr>`;
    }
    bookHtml+=`</table>`;
    bookHtml+=`<button>上一页</button>
                <button onclick="nextPage()">下一页</button>`;
    var section=document.createElement("section");
    section.innerHTML=bookHtml;
    document.getElementById("book").appendChild(section);
}

这样一个基本的ajax请求就搭起来了,然后就是我们分析的重点:“下一页”按钮:

function nextPage(){
    pageIndex++;
    makeRequest(pageIndex);
}

到此,如果不做任何处理的话,就不能够发挥浏览器返回、前进按钮的作用。
如果能够检测到用户点了后退、前进按钮的话,就可以做些文章:HTML5就有这么一个事件 window.onpopstate ,当用户单击前进后退按钮就会触发这个事件 —— 但是光这样还不够,还得传些参数,因为这个事件只能检测到你手动添加上去的url,而且我们返回到之前那个页面时得知道那个页面的pageIndex。HTML5里也有这样一个函数pushState:

window.history.pushState(state,title,url);

其中state是一个object,为当前页面的数据。title没有什么用。url为当前页面的url —— 一旦更改了这个url,浏览器地址栏的地址也会跟着变化(但页面不会刷新)。

还有就是页面load事件未触发之前,点击后退也不会触发popstate事件

于是我们这样做:

function nextPage(){
    pageIndex++;
    makeRequest(pageIndex);
    window.history.pushState({page:pageIndex},null,window.location.href);
}

然后去监听popstate事件:

window.addEventListener("popstate",function(event){
    var page=0;
    //state数据通过event传进来,这样就可以得到pageIndex
    if(event.state !== null){
        page=event.state.page;
    }
    makeRequest(page);
    pageIndex=page;
})

这样就会发现,按钮被激活了。

到这里就基本完工了。但是我们发现:在第二页点击刷新的话,首先会出现第一页,点击下一页,出现第二页。然后点返回按钮,发现还是第二页,再次点击时才会回到第一页。

打开控制台,会发现:点第一次返回时获取到的pageIndex仍然是1,即第二页。
我们可以理解为:对history,浏览器有一个队列,用来存放访问的记录,包括每个访问的网址还有state数据。一开始打开页面,队列的首指针指向page=0的位置,点下一页时,执行了pushState,在这个队列插入了一个元素,队首指针移向了page=1的位置。同时通过pushState操作记录了这个元素的url和state数据。
从这里可以看出,pushState最重要的作用还是给history队列插入元素,这样浏览器的后退按钮才不是置灰的状态,其次才是上面所说的存放数据。

那么当前我们最重要的就是“及时保存(缓存)数据 & 更换pageIndex”:
我们整合一下所用到的函数:

var pageIndex=window.localStorage.pageIndex || 0;

function nextPage(){
    window.localStorage,pageIndex=++pageIndex;
    makeRequest(pageIndex);
    window.history.pushState({page:pageIndex},null,window.location.href);
}

window.addEventListener("popstate",function(event){
    var page=0;
    //state数据通过event传进来,这样就可以得到pageIndex
    if(event.state !== null){
        page=event.state.page;
    }
    makeRequest(page);
    window.localStorage,pageIndex=page;
})

在改变pageIndex的同时,将其放到localStorage里,这样刷新页面时就可以获取到当前页的pageIndex。

还有一种方法是将其放到url参数里:通过改变当前网址。pageIndex从网址里面取:

var pageData=window.location.search.match(/page=([^&#]+)/);

var pageIndex=pageData ? +pageData[1] : 0;
function nextPage(){
    ++pageIndex;
    makeRequest(pageIndex);
    window.history.pushState({page:pageIndex},null,"?page="+pageIndex);
}

这样的好处在于,链接会跟着变,带着pageIndex参数的链接无论是前端渲染还是服务端渲染都可以实现。并且分享给别人时,打开页面也会直接看到同步的数据(比如跳转到第几页的数据页面)。

使用localStorage,唯一担心的不过就是用户开启了隐身/无痕模式(对localStorage的禁用)。


本文笔者原发于csdn: https://yunxiaomeng.blog.csdn.net/article/details/106747078
转载请注明出处!

相关文章

  • 前端性能优化指南

    前端性能优化指南 AJAX优化 缓存AJAX: 请求使用GET:当使用XMLHttpRequest时,而URL长度...

  • 前端性能优化实践:Ajax请求优化新体验

    说起来ajax,相信诸位都不会陌生 —— 这可是当下前端最火的技术之一。 ajax请求数据,将数据拿到前端页面上,...

  • 前端面试必问及加分点---性能优化篇

    如何进行网站性能优化 你有用过哪些前端性能优化的方法? 谈谈性能优化问题 代码层面的优化 前端性能优化最佳实践

  • 前端性能优化(中)

    性能优化调研系列文章 《前端性能优化(上)》 《前端性能优化(中)》 《前端性能优化(下)》 《前端性能优化(上)...

  • 前端性能优化(下)

    性能优化调研系列文章 《前端性能优化(上)》 《前端性能优化(中)》 《前端性能优化(下)》 《前端性能优化(中)...

  • 前端性能优化(上)

    性能优化调研系列文章 《前端性能优化(上)》 《前端性能优化(中)》 《前端性能优化(下)》 为什么要进行前端性能...

  • 2018.5面试总结

    问题1:前端性能优化 优化图 参考:掘金 1.1. http请求优化 优化手段1:合并请求合并请求的主要目的是减少...

  • 文摘-20170226

    前端 释义前端指南 性能优化腾讯HTTPS性能优化实践 vuevue早期源码学习系列之一:如何监听一个对象的变化 ...

  • 性能优化

    前端性能优化 一:主要是减少HTTP请求次数和请求大小,二:代码优化,有利于seo,扩展维护,减少性能消耗,[JS...

  • 前端性能优化

    前端性能优化 1.网络请求 DNS 查询优化 减少请求域名数量 减少请求数 合并文件 css 合并 js Spri...

网友评论

      本文标题:前端性能优化实践:Ajax请求优化新体验

      本文链接:https://www.haomeiwen.com/subject/eipyxktx.html