zoukankan      html  css  js  c++  java
  • js面试--ajax与性能优化

    1、javascript的同源策略

    一个脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议、端口号的组合

    协议:http ftp https
    主机名:localhost 127.0.0.1
    端口号:80
    http协议默认端口号:80
    https协议默认端口号:8083
    同源策略是用来保护我们的文件不被外来的域名随便串改
    同源策略带来的麻烦:ajax在不同的域名下的请求无法实现
    如果说想要请求其它来源的js文件,或者json数据,可以通过josnp来解决

    JSONP的实现原理:通过动态创建script表
    function jsonpCallback(result){
        console.log(var i in result){
            console.log(result[i])
        }
    }
    var JSONP=document.createElement('script');
    JSONP.type="text/javascript"
    JSONP.src="http://xxxxx.com/servies.php?callback=jsonpCallback"
    document.body.appendChild(JSONP);
    
    
    //php
    //服务端返回json数据
    $arr=array('a'=>1,'b'=>2,'c'=>3);
    $result=json_encode($arr);
    //动态执行回调函数
    $callback=$_GET('callback');
    echo $callback."($result)";

    、ajax 的基本概念

    了解这个概念,同步交互与异步交互
    同步交互:客户端浏览器给服务器发送一个请求,服务器返回一个页面,返回的页面会吧之前的界面给覆盖,我们把这种交互称为同步交互.
    异步交互:
    异步交互就是客户端浏览器给服务器发送一个请求,服务器返回数据,返回的数据不会吧之前的界面覆盖,我们把这种交互称为异步交互。
    Ajax 主要的应用场景,页面不刷新,就可以与服务端进行动态的数据交互。

    2、交互的原理
    我们在浏览器怎么给服务器发送请求,点击超链接,提交表单,浏览器地址输入地址,都是给服务器发送请求。实际上都是浏览器帮我去发送请求.

    3、ajax 跨域
    这个跨域. 我们要知道什么是跨域,跨域之后我们怎么去做处理
    跨域:假设我访问a 站点,在a站点得到一个页面,在a 站点的这个页面想去访问b 站点的资源,这个是就会产生一个跨域的效果,跨域浏览器是有安全限制的

    jsonp (xmlhttpRequest去创建一个script标签),然后通过script去发送请求,服务器返回了数据,返回的数据浏览器会直接以javascript的方式去解析服务端返回的数据 

    $('.btn').on('click',function(){
         var phone=$('#phone').value()
            $.ajax({
                 type:'get',
                 url:"https://api.jisuapi.com/shouji/query",
                 data:"appkey=7ca5f245245f2b88&shouji="+phone,
                 dataType:"jsonp",//开启跨域
                 success:function(result){
                     console.log(result)
                 }     
            })
     })

    jsonp底层: 只支持get,不支持post

            //定义成一个全局的函数
            function getInfo(obj){
                console.log(obj);
    
            }
    
            document.querySelector("input").onclick=function(){
                  //点击这个按钮,我给jd 发送请求.
                  //http://www.jd.com/jd.php
                  //假设我使用XMLHttpRequest 很明显就跨域了
    
                 var script=document.createElement("script");
    
                 //这个请求暂时是没有发送出去.
                 //把这个标签挂载到页面上面才能够发送请求callback 跨域的通用的参数名称.
                 script.src="http://www.jd.com/jd.php?callback=getInfo";
    
                 //因为现在服务端给我返回的数据{"username":"zhangsan","age":11}
                 //客户端以js 的方式去解析这个数据{"username":"zhangsan","age":11}
                 //不符合js 的语法,所以就报错了.
    
                 document.body.appendChild(script);
    
                  //客户端浏览器得到是这样的数据getInfo({username: "zhangsan", age: 11})
                  //以js 的方式去解析,就会去调用getInfo  的函数.
    
                 //我现在的目的是想在页面里面得到这个服务端返回的数据
                 //1:客户端给服务端传递一个回调函数 ,它还需要定义一个函数
                 //2:服务端返回的是一个回调函数的调用,并且将服务端的数据包在这个函数的调用里面.
    
                  //现在我只能解决get 方式的跨域,我们把这个种跨域叫做jsonp
                  //把数据作为参数传递过来
                  //为什么只能解决get 方式的跨域,底层使用script 标签发送请求
                  //src href 这些发送的请求都是get 请求.
                  //jsonp ,客户端给服务端传递一个回调函数,服务端返回的是一个回调函数的调用,并且将数据放在回调函数里面作为参数传递过来.
            }

    现在采用的跨域方案是jsonp jsonp 只支持get 方式的跨域,并不支持post,
    如果我要给跨域的服务器传递非常多数据,get 对请求的数据的大小有限制,传不过去.
    我们就要处理post 方式的跨域
    使用一个叫做cors 的方案 跨域资源共享. 其实这个是需要在服务器端进行一个配置,其实就服务端给客户端一个响应头,就搞定.

     jquery只支持jsonp,不支持cors

     

    cors 

    实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
    服务器设置请求头:Access-Control-Allow-Origin启用CORS。

    参考:https://www.cnblogs.com/itmacy/p/6958181.html

    cors详细解释:https://www.cnblogs.com/loveis715/p/4592246.html

    4、ajax用在哪些地方

    360 的案例
    输入关键字,输入关键字,触发一个事件,执行一个方法,调用JavaScript的这个api 。
    通过XMLHttpRequest 给服务器发送请求,通过XMLHttpRequest 接收数据.
    然后接收到数据之后,通过dom 把这个数据写到页面上面,通过这样的过程来完成异步交互的操作.

    Ajax,检测用户名是否存在,失去焦点发送请求

    Ajax 也可以用来做性能优化,比如我一个页面非常庞大,这个页面不可能一次加载完毕.
    实现一个滚动加载

    5、原生ajax

    Ajax 是什么? (用来实现客户端与服务器端的异步通信效果,实现页面的局部刷新

    如何创建一个Ajax?

    /*
        第一步:创建ajax对象
            var xhr = new XMLHttpRequest();
            //var xhr = new ActiveXObject('Microsoft.XMLHTTP'); ie6一下
    
        第二步:请求准备
            xhr.open( 'get' , 'firstAjax.txt' , true );
                参数1:请求方式 get/post
                    在form提交的时候:
    Get 把传输数据放在url后面 ,会有缓存,隐私会被暴露出来
    (get.php?usermane=aa&age=33)
                        post把数据放在头文件里面 用来往后端提交数据,不会有缓存;只有往后端获    取数据才会有缓存;
                       一般用post是提交数据,如果获取数据需要提交一些参数才能获取,而这些参数数据又不想暴露在地址栏,那就可以用post了
                参数2:请求路径
                参数3:是否异步
                    true 异步 请求的过程不会影响后面程序的执行
                    false 同步  当你后续代码要用到跟前面挂钩时,用同步
        
        第三步:正式发送请求
            xhr.send();
        
        第四步:监听请求状态
            xhr.readyState :请求状态码
                0 :请求还没发生(open执行之前)
                1 :请求已经建立,还没发送(执行了open)
                2 :请求已经发送,正在处理(执行了send)
                3 :请求处理中,有一部分数据可以用,但还有没有完成的数据。
                4 :请求完全完成
    
            onreadystatechange :请求状态码发生改变的时候触发
    
            xhr.responseText : 返回的数据
    
            xhr.status : HTTP状态码
    */
    var xhr=null;
    if(window.XMLHttpRequest){ //判断是window底下的属性是否存在
        xhr=new XMLHttpRequest();
    }else{
        xhr=new ActiveXObject('Microsoft.XMLHTTP');
    }
    // var xhr = new XMLHttpRequest();
    xhr.open( 'get' , 'test.php' , true );
    xhr.send();
    xhr.onreadystatechange = function(){
        if ( xhr.readyState == 4 )
        {
            if ( xhr.status >= 200 && xhr.status < 300 )
            {
               console.log(xhr.responseText)
            }else
            {
                alert( '请求好像遇到了点问题,状态码:' + xhr.status );
            };
        }
    };
    Post:
    xhr.open('post','1post.php',true);
    xhr.setRequestHeader('content-type','application/x-www-form-urlencoded'); //告诉后端发送数据的编码类型
    xhr.send('username=leo&age=30');//post方式,数据放在send()里面作为参数传递
    xhr.onreadystatechange=function(){
    if(xhr.readyState==4){
        if(xhr.status==200){
        alert(xhr.responseText)
        }else{
            alert('出错了,Err'+xhr.staus)
        }
    }
    }

    2、Json:是一种轻量级的数据交换格式, 数据格式简单, 易于读写, 占用带宽小

    JSON字符串转换为JSON对象:
    var obj =eval('('+ str +')');
    var obj = str.parseJSON();
    var obj = JSON.parse(str);
     
    JSON对象转换为JSON字符串:
    var last=obj.toJSONString();
    var last=JSON.stringify(obj);

    5、简述ajax 的过程。

    1. 创建XMLHttpRequest对象,也就是创建一个异步调用对象
    2. 创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
    3. 设置响应HTTP请求状态变化的函数
    4. 发送HTTP请求
    5. 获取异步调用返回的数据
    6. 使用JavaScript和DOM实现局部刷新

    6、http状态码

    1XX: 一般用来判断协议更换或者确认服务端收到请求这些 
    100: 服务端收到部分请求,若是没有拒绝的情况下可以继续传递后续内容
    101: 客户端请求变换协议,服务端收到确认
    2xx: 请求成功,是否创建链接,请求是否接受,是否有内容这些 
    200: (成功)服务器已成功处理了请求。
    201: (已创建)请求成功并且服务器创建了新的资源。
    202: (已接受)服务器已接受请求,但尚未处理。
    204: (无内容)服务器成功处理了请求,但没有返回任何内容。
    3XX: 一般用来判断重定向和缓存 
    301: 所有请求已经转移到新的 url(永久重定向),会被缓存
    302: 临时重定向,不会被缓存
    304: 本地资源暂未改动,优先使用本地的(根据If-Modified-Since or If-Match去比对服务器的资源,缓存)
    4XX: 一般用来确认授权信息,请求是否出错,页面是否丢失 
    400: 请求出错
    401: 未授权,不能读取某些资源
    403: 阻止访问,一般也是权限问题
    404: 页面丢失,资源没找到
    408: 请求超时
    415: 媒介类型不被支持,服务器不会接受请求。
    5XX: 基本都是服务端的错误 
    500: 服务端错误
    502: 网关错误
    504: 网关超时

    4、页面编码和被请求的资源编码如果不一致如何处理?

    对于ajax请求传递的参数,如果是get请求方式,参数如果传递中文,在有些浏览器会乱码,不同的浏览器对参数编码的处理方式不同,所以对于get请求的参数需要使用 encodeURIComponent函数对参数进行编码处理,后台开发语言都有相应的解码api。对于post请求不需要进行编码

    存储问题:
    1、如何实现浏览器内多个标签页之间的通信?
    调用localstorge、cookies等本地存储方式

     
    ➤异步
    1、简述同步和异步的区别
    
    
    同步是阻塞模式,异步是非阻塞模式。
    
    
    同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
    
    
    异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
    2、什么是单线程,和异步的关系?
    单线程---只有一个线程,同一时间只能做一件事,两段JS不能同时执行
    原因是为了避免DOM渲染的冲突
    解决方案---异步
    其他:
    为什么js是单线程?单线程也为了避免DOM渲染的冲突
    为什么会有异步?异步是为了避免页面被阻塞(比如ajax要等到请求,服务器返回慢就会阻塞后面的事件执行)
    异步的问题:
    没有按照书写方式执行,可读性差
    callback中不容易模块化
    为什么单线程是避免DOM渲染冲突
    浏览器需要渲染DOM,
    JS可以修改DOM结构
    JS执行的时候,浏览器DOM渲染会暂停
    两段JS也不可能同时执行(都修改DOM就冲突了)
    webworker支持多线程,但是不能访问DOM
    (所以必须是单线程的,起多个线程的时候会造成Dom冲突)
    //循环运行期间,JS执行和DOM渲染暂时卡顿
    var i,sum=0;
    for( i=0;i<1000000;i++){
    sum++
    }
    console.log(sum)
    
    
    //单线程,同一时间只能做一件事
    //alert不处理,js执行和DOM渲染暂时卡顿
    console.log(100);
    alert('hello world');
    console.log(200)
    
    //解决方案:异步
    console.log(100);
    setTimeout(function(){
        console.log(200)       //1000s之后执行
    },1000)                    //先不管它,先让其它js代码运行
    console.log(300)
    console.log(400)
    
    //ajax
    console.log(100)
    $.ajax({
        url:'xxx',
        success:function(result){   //ajax加载完才执行
            console.log(result)    //先不管它,先让其它js代码运行
        }
    })
    console.log(300)
    console.log(400)
    3、什么是event-loop?(事件循环、事件轮循)
    事件轮询,JS实现异步的具体解决方案 (异步就是通过 事件轮询 方式来解决的)
    同步代码,直接执行
    异步函数放在 异步队列 中
    待同步函数执行完,轮询执行 异步队列 的函数
    /*先走主进程,再看异步队列有没有异步函数,发现只有 function(){ console.log(1) },
    暂时还没有第一个定时器的,因为要等100ms才放入异步队列,所以先把第二个定时器拿到主进程中执行,再去异步队列看有没有异步函数,一直监视*/
    $.ajax({
        url:'xxxx',
        success:function(reslut){  //等ajax加载完成时放入异步队列,有可能在定时器前面或者后面,或者在第一个定时器前
            console.log('a')
        }
    })
    
    setTimeout(function(){
        console.log(100)  //200ms 才放入异步队列,执行的是function(){ console.log(100) }
    },200)
    
    setTimeout(function(){
        console.log(1)  //立即放入异步队列 function(){ console.log(1) }
    })
    
    console.log(200)  //主进程
    4、是否用过jquery的Deferred(延迟)?
    不是所有网站都用ajax、vue这些,还需要jquery的Deferred
    promise就是从deferred进化来的
    //jquery1.5之前,现在也这么写
    var ajax=$.ajax({
        url:'data.json',
        success:function(){
            console.log('success1')
            console.log('success2')
            console.log('success3')
        },
        error:function(){
            console.log('error')
        }
    })
    console.log(ajax) //返回一个XHR对象
    
    //1.5之后
    var ajax=$.ajax('data.json')
    ajax.done(function(){
        console.log('success1')
    }).fail(function(){
        console.log('error')
    }).done(function(){
        console.log('success2')
    })
    console.log(ajax) //返回一个deferred对象
    
    //还可以这么写,很像promise的写法
    var ajax=$.ajax('data.json')
    ajax.then(function(){
        console.log('success1')
    }.function(){
        console.log('error1')
    })
    .then(function(){
        console.log('success2')
    }.function(){
        console.log('error2')
    })
    
    /*
       1.5的变化
       无法改变JS异步和单线程的本质
       只能从写法上杜绝callback这种形式
       它是一种语法糖形式,但是解耦了代码
       很好的体现:开放封闭原则
    
    */
    /*  var wait=function(){
                var task=function(){
                    console.log('执行完成')
                    //dosomeing1
                    //dosomeing2
                }
                setTimeout(task,2000)
            }
            wait()
         */
    
            //怎么封装成Deferred
            function waitHandle(){
                //定义
                var dtd=$.Deferred()
                var wait=function(dtd){
                    var task=function(){
                         console.log('执行完成')
                         //成功
                        dtd.resolve()
                        //失败
                        //dtd.reject()
                    }
                    setTimeout(task,2000)
                   //wait返回
                   return dtd
                }
                //最终返回
                return wait(dtd)
            }
            var w=waitHandle()
            w.then(function(){
                console.log('ok 1')
            },function(){
                console.log('err 1')
            })
            w.then(function(){
                console.log('ok 2')
            },function(){
                console.log('err 2')
            })
    
            /*
            总结,dtd的api可分为两类,用意不同
            第一类:dtd.resolve dtd.rejet(主动要做的事)
            第二类:dtd.then dtd.done dtd.fail (dtd.then 是被动监听 reslove或者reject   )
            这两类应该分开,否则后果很严重
            可以在上面代码最后执行dtd.reject()试下结果
            */
    promise和deferred的区别
    deferred对象有resolve reject 穿插的元素 done fail 这种监听函数,这些函数混在一块是不行的,很容易被外边串改,
    我们通过生成一个promise对象来进行隔离,promise只能被动监听,没有权利修改
    //使用dtd.promise()
            //已封装好的A员工
            function waitHandle(){
                //定义
                var dtd=$.Deferred()
                var wait=function(dtd){
                    var task=function(){
                         console.log('执行完成')
                         //成功
                        dtd.resolve()
                        //失败
                        //dtd.reject()
                    }
                    setTimeout(task,2000)
                   //wait返回
                   return dtd.promise() //注意,这里返回的是promise 而不是直接返回deferred对象
                }
                //最终返回
                return wait(dtd)
            }
            //使用B员工
            var w=waitHandle() //w接收的是一个promise对象
            w.reject()
            $.when(w).then(function(){
                console.log('ok 1')
            },function(){
                console.log('err 1')
            })
     
    性能优化:

    1、 为什么利用多个域名来存储网站资源会更有效?
    CDN缓存更方便
    突破浏览器并发限制
    节约cookie带宽
    节约主域名的连接数,优化页面响应速度
    防止不必要的安全问题

    其它
    2、浏览器怎么知道是304缓存
    浏览器在发请求前,感觉自己可能缓存了某个文件,就先把自己缓存的文件信息放在请求头里。
    服务器在发送响应前,对比一下这个文件信息,发现浏览器缓存的文件就是它,于是决定不发送整个文件内容,直接告诉浏览器 304 。
    浏览器接收到 304 时,就知道原来我缓存的就是跟服务器端一样的文件,于是就直接拿本地缓存来用了。
    如果服务器发现浏览器的缓存文件信息已经是旧的了,服务器就直接正常的发送文件内容,浏览器正常的接收文件内容了。



  • 相关阅读:
    Ecshop屏幕wap
    SQLite命令
    初识SQLite
    last_insert_id()
    php中的全局变量global(低级错误啊)
    在搜索框加入语音搜索
    解压zip文件出现bash:unzip:commond not found
    DataView.RowFilter使用
    设计自己的模板引擎(一)模板替换中的嵌套循环处理
    没完没了的Cookie,读懂asp.net,asp等web编程中的cookies 
  • 原文地址:https://www.cnblogs.com/sayidf/p/9202143.html
Copyright © 2011-2022 走看看