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 时,就知道原来我缓存的就是跟服务器端一样的文件,于是就直接拿本地缓存来用了。
如果服务器发现浏览器的缓存文件信息已经是旧的了,服务器就直接正常的发送文件内容,浏览器正常的接收文件内容了。

 




posted @ 2018-06-24 21:46  sayid~  阅读(260)  评论(0编辑  收藏  举报