一个通用广告脚本数据加载的容错
最基本的需求
写一个通用的广告脚本文件,传递不同的广告ID,加载对应的数据出来,上报数据,最后显示出来
最简单的做法
每个站点,直接请求广告地址,带上不同参数,例如这样:
    var script = document.createElement("script");
    script.src = 'ad.com?id=id1&callback=cb';
    document.body.appendChild(script);
    function cb(param){
        //do something
        new Image().src = "report.com?id=id1";
    }
以上做法存在的问题:
- 每个站点都需要记住请求的地址,万一地址改了,全都要改
- 每个站点,都需要自己去写请求,以及回调
- 每个站点,都需要自己去上报数据
- 请求失败了,怎么办?
- 请求时间很长,怎么办?
站点的使用,更应该关心的是:
- 统一的接口
- 只需要传ID和回调函数
- 返回需要的数据进行渲染页面
- 错误、失败、上报、超时等不需要关心
我们可以这样做
1、统一处理请求
采用类
jQuery的方式来进行jsonp请求,增加超时和错误监控
    //简易版jsonp
    ;var __GetScript = function(){
    
        //发送请求(闭包)
        //param object json参数
        //param.url 请求的地址
        //param.data 请求的参数
        //param.success 请求成功的回调
        //param.error 请求失败的回调
        function send(param){
        
            //随机函数名字,类似jquery
            var random = "script" + Math.floor(Math.random() * 100000 + 100000);
            //计时器Id,用于超时abort
            var timeId = 0;
            //创建script脚本
            var script = document.createElement("script");
            script.type = "text/javascript";
            //绑定脚本错误事件
            var onerror = script.onerror = function(){
                //如果计时器是空,则表示请求成功了
                if(!timeId)return false;
                clearTimeout(timeId);
                //回调用户错误函数
                param.error();
                //移除script标签以及对应成功函数
                document.body.removeChild(script);
                window.random = null;
            };
            //绑定全局回调成功函数
            window[random] = function(){
                
                if(!timeId)return false;
    
                clearTimeout(timeId);
                //将jsonp的参数列表,返回给用户的回调函数
                try{
                    param.success.apply(null,arguments);
                }
                catch(e){
                    //用户回调执行出错,执行错误函数
                    param.error();
                }
                //移除script标签以及对应成功函数
                document.body.removeChild(script);
                window.random = null;
            }
            
            //超时则直接返回失败,这里设置了3秒
            timeId = setTimeout(function(){
    
                //触发onerror事件
                onerror();
                
                timeId = 0;
                
            },3000);
            //script的请求,一定是在最后
            script.src = param.url + "?" + param.data + "&callback=" + random;
    
            document.body.appendChild(script);
        }
        //返回请求接口
        return send;
    }();
    
    //调用demo,这样看起来,就跟jquery的差不多了
    __GetScript({
        url : 'ad.com',
        data : 'id=id1',
        success : function(data){},
        error : function(){}
    });
2、超时、请求失败
服务器挂了,服务器卡住了,那广告位总不能显示空白吧?
- 用户第一次访问,服务器就挂了(这种表示无奈),显示一个加载失败的提示文案或者图标之类的,统一在广告位加上一个标识来处理 
- 用户第一次访问成功过,但之后第二次访问的时候才挂的,那么可以考虑使用上一次成功的数据来展示 - 2.1 每次请求成功,缓存成功数据,格式采用 - json格式,旧版使用- json2来支持
 2.2 IE使用- userData,标准浏览器用- localStorage
 2.3 合并新请求的数据与旧的缓存数据
    //拉取数据成功
    function getDataSucc(data,pos,cb_list){
        //移除正在请求的提示
        $(".adbase-ctn").css("background","none");
        
        //获取本地缓存数据
        var locData = getDataByLoc(pos);
        //合并与覆盖最新数据到本地中
        locData = extendData(locData,data);
        //记录当前数据,JSON对应在旧浏览器需要用第三方库`json2`
        LocalData.set(pos,JSON.stringify(locData));
        //回调给用户
        for(var i=0;i<cb_list.length;i++){
            cb_list[i](true,locData);
        }
    }
    //获取本地缓存数据
    function getDataByLoc(pos){
        //LocalData对象是操作userData和localStorage
        var data = LocalData.get(pos);
        if(!data)return {};
        //从缓存中读取的字符串,转成json对象
        return JSON.parse(data);
    }
    //合并新旧数据
    function extendData(oldData,newData){
        for(var key in newData){
            //本地没有这个数据,合并
            if(!oldData[key] || oldData[key].length < 1){
                oldData[key] = newData[key];
                continue;
            }
            //本地跟新数据都有,合并
            if((oldData[key] && oldData[key].length) && (newData[key] && newData[key].length)){
                oldData[key] = newData[key];
                continue;
            }
            //新数据没有,本地数据有,不合并
            if((oldData[key] && oldData[key].length) && (!newData[key] || newData[key].length < 1)){
                continue;
            }
            //本地没有,新数据也没有
            if((!newData[key] || newData[key].length < 1) && (!oldData[key] || oldData[key].length < 1)){
                oldData[key] = [];
            }
        }
        return oldData;
    }
3、其它收尾细节
处理完请求和缓存这两块主要的,还有一些细节需要考虑
- 在请求成功后,统一上报数据,该请求可以稍微往后,用setTimeout
- 在有数据的情况下(可能只是部分),需要针对没有数据的广告位进行显示失败的提示,例如:
    //监测是否存在空数据的广告位
    function checkNoDataCtn(){
        //循环遍历容器是否有子元素
        $(".adbase-ctn").each(function(index,item){
            if($(item).contents().length < 1)$(item).css("background","url(http://res.nie.netease.com/comm/js/nie/util/img/error.png) center center no-repeat");
        });
    }
- IE7的userData的key只支持的规则和定义变量一致,不能带有类似,,;这种分隔符
- 低版本的IE浏览器,即使script请求失败了,也不会调用onerror事件,统一采用超时机制就好了
PS:更多代码详情,请参考:adbase
手机阅读请扫描下方二维码:
__GetScript 这个函数,里面的success方法没起作用。
1
555
1
1
1
1
1
1
1
1
1
1
1
1
1
1
不错哦,赞一个,求认识,求回访 http://www.xevip.cn
555
555
文章很好~!赞 http://www.viplinger.cn
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
gyskureniqpnfpnlsiiq
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
555
文章很好~!赞 欢迎回访:www.3gwb.com
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
12345678 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1
1
1
1
555
1
1
1
1
1 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1 
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
  
1
1
1
555
1
555
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1