浏览器相关

334 阅读12分钟

目标

  • 浏览器内置JS对象详解
  • 浏览器事件模型详解
  • 浏览器请求相关内容详解

知识要点

BOM 浏览器对象模型

Browser Object Model(浏览器对象模型),浏览器模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构,就是浏览器提供的 API 其主要对象有:

  1. window 对象——BOM 的核心,是 js 访问浏览器的接口,也是 ES 规定的 Global 对象
  2. location 对象:提供当前窗口中的加载的文档有关的信息和一些导航功能。既是 window 对象属 性,也是 document 的对象属性
  3. navigation 对象:获取浏览器的系统信息
  4. screen 对象:用来表示浏览器窗口外部的显示器的信息等
  5. history 对象:保存用户上网的历史信息

window对象

整个浏览器对象模型的核心,其扮演着既是接口又是全局对象的角色

window对象.jpg

窗口位置

screen对象

screen对象.png

window对象_窗口位置.png

大小

window对象_窗口大小.png

定时器

setTimeout

setInterval

Location 对象

提供当前窗口中的加载的文档有关的信息和一些导航功能。既是 window 对象属性,也是 document 的对象属性

location 对象的主要属性:

location对象.png

Navigation 对象

navigation 接口表示用户代理的状态和标识,允许脚本查询它和注册自己进行一些活动

navigation对象.png

History 对象

history 对象保存着用户上网的历史记录,从窗口被打开的那一刻算起,history 对象是用窗口的浏览历史用文档和文档状态列表的形式表示。

history对象.png

浏览器事件捕获,冒泡

  • 捕获阶段
  • 目标阶段
  • 冒泡阶段

事件模型.jpg

addEventListener(eventName:string,callback:Function,true|false)

第三个参数, 如果为true,就是代表在捕获阶段执行。如果为false,就是在冒泡阶段进行

阻止事件传播

  • e.stopPropagation()

大家经常听到的可能是阻止冒泡,实际上这个方法不只能阻止冒泡,还能阻止捕获阶段的传播。

  • stopImmediatePropagation() 如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation() 方法,则当前元素剩下的监听函数将不会被执行

阻止默认行为

e.preventDefault()

e.preventDefault()可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为

兼容性

attachEvent——兼容:IE7、IE8; 不支持第三个参数来控制在哪个阶段发生,默认是绑定在冒泡阶段 addEventListener——兼容:firefox、chrome、IE、safari、opera;

绑定事件的运用,以及封装一个多浏览器兼容的绑定事件函数

class BomEvent {
    constructor(element) {
        this.element = element;
    }
​
    addEvent(type, handler) {
        if (this.element.addEventListener) {
            //事件类型、需要执行的函数、是否捕捉
            this.element.addEventListener(type, handler, false);
        } else if (this.element.attachEvent) {
            this.element.attachEvent('on' + type, function () {
                handler.call(element);
            });
        } else {
            this.element['on' + type] = handler;
        }
    }
​
    removeEvent(type, handler) {
        if (this.element.removeEnentListener) {
            this.element.removeEnentListener(type, handler, false);
        } else if (element.datachEvent) {
            this.element.detachEvent('on' + type, handler);
        } else {
            this.element['on' + type] = null;
        }
    }
}
// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
function stopPropagation(ev) {
    if (ev.stopPropagation) {
        ev.stopPropagation(); // 标准w3c
    } else {
        ev.cancelBubble = true; // IE
    }
}
// 取消事件的默认行为
function preventDefault(event) {
    if (event.preventDefault) {
        event.preventDefault(); // 标准w3c
    } else {
        event.returnValue = false; // IE
    }
}

大家常见的一个面试题可能是ul + li,点击每个li alert对应的索引,这里就给大家来写一下看看

  • 先来给每个li绑定事件
  • 再来写一个事件委托的方式

冒泡实例

<!DOCTYPE html><html>
    <head>
        <meta charset="UTF-8">
    </head>
  <body>
    <div id="parent" class="flex-center">
        parent
        <p id="child" class="flex-center">
            child
            <span id='son' class="flex-center">
                son
                <a href="https://www.baidu.com" id="a-baidu">点我啊</a>
            </span>
        </p>
    </div>
  </body>
  <script type="text/javascript" src="index.js"></script>
  <style>
    #parent {
        background-color: bisque;
        width: 700px;
        height: 700px;
​
    }
​
    #child {
        background-color: chocolate;
        width: 500px;
        height: 500px;
    }
​
    #son {
        background-color: crimson;
        width: 300px;
        height: 300px;
    }
​
    .flex-center {
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 20px;
    }
  </style>
</html>

index.js

const parent = document.getElementById("parent");
const child = document.getElementById("child");
const son = document.getElementById("son");
// const baidu = document.getElementById("a-baidu");// baidu.addEventListener('click', function (e) {
//     e.preventDefault();
// })window.addEventListener("click", function (e) {
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);//capture: 默认值为false(即 使用事件冒泡). 是否使用事件捕获;或者在捕获时执行,还是在冒泡时执行
​
parent.addEventListener("click", function (e) {
    // e.stopPropagation();
​
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
​
child.addEventListener("click", function (e) {
    console.log("child 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
​
son.addEventListener("click", function (e) {
    console.log("son 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
​
window.addEventListener("click", function (e) {
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
​
parent.addEventListener("click", function (e) {
    console.log("parent 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
​
child.addEventListener("click", function (e) {
    console.log("child 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
​
son.addEventListener("click", function (e) {
    console.log("son 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

ajax 及 fetch API 详解

XMLHTTPRequest

ajax使用XMLHttpRequest实现demo例子

let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');
​
// request state change event
xhr.onreadystatechange = function () {
    // request completed?
    if (xhr.readyState !== 4) return;
​
    if (xhr.status === 200) {
        // request successful - show response
        console.log(xhr.responseText);
    } else {
        // request error
        console.log('HTTP error', xhr.status, xhr.statusText);
    }
};
​
// xhr.timeout = 3000; // 3 seconds
// xhr.ontimeout = () => console.log('timeout', xhr.responseURL);
​
// progress事件可以报告长时间运行的文件上传
// xhr.upload.onprogress = p => {
//     console.log(Math.round((p.loaded / p.total) * 100) + '%');
// }
​
// start request
xhr.send();

使用ts 手写一个ajax

使用的 ts, XMLHttpRequest||ActiveXObject (microsoft的xmlHTTP)(兼容), promise, encodeURIComponent来编码url query, xhr.onreadystatechange来接收response, xhr.timeout设置超时,设置xhr.ontimeout来reject

interface IOptions {
    url: string;
    type?: string;
    data: any;
    timeout?: number;
}
​
function formatUrl(json) {
    let dataArr = [];
    json.t = Math.random();
    for (let key in json) {
        dataArr.push(`${key}=${encodeURIComponent(json[key])}`)
    }
    return dataArr.join('&');
}
​
export function ajax(options: IOptions) {
    return new Promise((resolve, reject) => {
        if (!options.url) return;
​
        options.type = options.type || 'GET';
        options.data = options.data || {};
        options.timeout = options.timeout || 10000;
    
        let dataToUrlstr = formatUrl(options.data);
        let timer;
    
        // 1.创建
        let xhr;
        if ((window as any).XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else {
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }
    
        if (options.type.toUpperCase() === 'GET') {
            // 2.连接
            xhr.open('get', `${options.url}?${dataToUrlstr}`, true);
            // 3.发送
            xhr.send();
        } else if (options.type.toUpperCase() === 'POST') {
            // 2.连接
            xhr.open('post', options.url, true);
            xhr.setRequestHeader('ContentType', 'application/x-www-form-urlencoded');
            // 3.发送
            xhr.send(options.data);
        }
    
        // 4.接收
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                clearTimeout(timer);
                if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                    resolve(xhr.responseText);
                } else {
                    reject(xhr.status);
                }
            }
        }
    
        if (options.timeout) {
            timer = setTimeout(() => {
                xhr.abort();
                reject('超时');
            }, options.timeout)
        }
​
        // xhr.timeout = options.timeout;
        // xhr.ontimeout = () => {
        //     reject('超时');
        // }
    });
}
​

fetch

  • 默认不带cookie
  • 错误不会reject
  • 不支持超时设置
  • 需要借用AbortController中止fetch
//默认不带cookie
fetch('http://domain/service',{
    method:'GET',
    credentials:'same-origin'
}).then(response=>{
    if(response.ok){
        return response.json();
    }
    throw new Error('Network response was not ok.');
})
.then(json=>console.log(json))
.catch(error=>console.error('error',error))
/ 错误不会reject
// HTTP错误(例如404 Page Not Found 或 500 Internal Server Error)不会导致Fetch返回的Promise标记为reject;.catch()也不会被执行。
// 想要精确的判断 fetch是否成功,需要包含 promise resolved 的情况,此时再判断 response.ok是不是为 true//不支持直接设置超时,可以用promise
function fetchTimeOut(url,init,timeout=3000){
    return new Promise((resolve,reject)=>{
        fetch(url,init)
        .then(resolve)
        .catch(reject);
        setTimeout(reject,timeout)
    })
}
​
// 中止fetch
const controller = new AbortController();
​
fetch(
        'http://domain/service', {
            method: 'GET',
            signal: controller.signal
        })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.error('Error:', error));
​
controller.abort();
​

常见的浏览器请求/响应头/错误码解析

request header

:method: GET :path: /solar-comment/api/comment/tutor-primary-activity/senior-recommend/users/self?tagSource=&productId=351& appId=0 :scheme: https accept: application/json, text/plain, / accept-encoding: gzip, deflate, br cache-control: no-cache cookie: deviceId=c122305d338525616baea870cc76dd5b; abSeed=843447469b71b0978db580220c952c10; userid=172270653; persistent=3411agNdImBJd8GjTW6bWT9Vg0U2yoaka3Lp8sSCiv9B6MDvr27fL4o50ha+Pfuhi1y4/Gg8aRN3FEP+VV4jWA==; sid=5530384168693043754; sess=QvrAQ0Cq+EcDQQPTer2XHlv4fhIRaW/YCb/e4pz/I+vzKp85mI2ukPUBIuGweXj5sq8HhuYQtf03DxK4dphwkOyBKovyUyC5I8t9exQw6Aw= origin: m.yuanfudao.biz referer: m.yuanfudao.biz/primary/mar… 来自那个页面 user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1

response header

access-control-allow-credentials: true access-control-allow-origin: m.yuanfudao.biz content-encoding: gzip content-type: application/json;charset=UTF-8 date: Thu, 06 Aug 2020 08:15:05 GMT set-cookie: sess=QvrAQ0Cq+EcDQQPTer2XHlv4fhIRaW/YCb/e4pz/I+uSfZtum4dPp9q4HJL5o+GWuDXHXQLQF2JrIgwzZPaZHWal4qYZy/cfW0Sle/fyB/w=;domain=.yuanfudao.biz;path=/;HttpOnly set-cookie: userid=172270653;domain=.yuanfudao.biz;path=/;HttpOnly status: 200

status

200 get 成功 201 post 成功 301 永久重定向 302 临时重定向 304 协商缓存 服务器文件未修改 400 客户端请求有语法错误,不能被服务器识别 403 服务器受到请求,但是拒绝提供服务,可能是跨域 404 请求的资源不存在 405 请求的method不允许 500 服务器发生不可预期的错误

补充知识点

Bom

  • BOM 浏览器对象模型 (用于访问和操作浏览器窗口)

    • 弹出新浏览器窗口
    • 移动,缩放,关闭浏览器窗口
    • 提供浏览器详细信息 navigator对象
    • 加载页面的详细信息 location对象
    • 用户显示器分辨率详细信息
    • cookies支持
    • 自定义对象 如 XMLHttpRequest
  • 核心对象是window, 表示浏览器的一个实例,
  • 访问浏览器的一个接口
  • Global对象
  • 任何一个对象,变量和函数,都以window作为Global对象

窗口关系及框架

  • 每个框架都有自己的window对象, 保存在frames集合中

    <html>
    <frameset>//弃用
    <frame src='frame.html'>
    </frameset>
    </html>
    

    窗口位置

  • screenLeft属性,窗口相对于屏幕左边的位置(火狐 screenX)

  • screenTop属性,窗口相对于屏幕上边的位置(screenY)

窗口大小

  • innerWidth 页面视图区的大小,减去边框的宽度 移动上是屏幕上可见页面区域的大小

  • innerHeight

  • outerWidth

  • outerHeight

    导航和打开窗口

window.open(url)

location对象

  • window.location , document.localtion引用的是同一个对象
  • host 'www.wrox.com:80'
  • hostname 'www.wrox.com'
  • href ‘http:/ww.wrox.com’
  • pathname '/abd/'
  • port
  • protocol http
  • search '?q=javascript' //使用多 解析查询字符串参数
function getQueryStringArgs() {
    var qs = location.search.length > 0 ? location.search.substring(1) : '',
        args = {},
        items = qs.length ? qs.split('&') : [],
        item = null,
        name = null,
        i = 0,
        len = items.length;
    for (i = 0; i < len; i++) {
        item = items[i].split('=');
        //查询字符串被编译过,要解码
        name = decodeURIComponent(item[0]);
        value = decodeURIComponent(item[1]);
        if (name.length) {
            args[name] = value;
        }
    }
    return args;
}
console.log(getQueryStringArgs())

位置操作,打开新的地址

localtion.assign('www.wrox.com') //localtion.href, window.location 其实调用的都是assign方法 window.location= 'www.wrox.com'; localtion.href = 'www.wrox.com'

重新加载

localtion.reload();

navigator对象

识别客户端浏览器

检测插件

navigator.plugins 是一个插件数组,每个元素有name

客户端检测

引擎

识别平台 windows, Max Unix

识别移动设备

识别游戏系统

##Ajax 与Comet, XMLHttpREquest

##XMLHttpREquest 用于访问请求api

xhr.open('get','example.php',fasle)
xhr.send(null);
if(xhr.status>=200&&xhr.status<300||xhr.status==304){
    
}
  • 启动一个请求,准备发送,xhr.open 三个参数, 1.请求类型,2.请求的url,3.是否异步发送请求
  • xhr.send(body) 发送请求,如果不需要发送数据, body参数可以传null

同步发送时,JavaScript代码会等到服务器相依之后继续执行

返回的数据

  • responseText 作为响应主体返回的文本
  • responseXML 如果响应的内容是‘text/xml’ 或者‘application/xml’ ,属性保存返回的结果
  • status 响应的HTTP状态
  • statusText Http状态的说明

发送异步请求

readyState属性,表示请求/响应过程的当前活动阶段

  • 0 未初始化。未调用open
  • 1 启动,调用open,未调用send
  • 2 发送,调用send,未收到响应
  • 3 接收,接收到部分响应数据
  • 4 完成,已经接收到全部响应数据,而且已经在客户端使用
var xhr = createXHR();
//利用dom0级方法为xhr对象添加事件处理程序
xhr.onreadystatechange = function(){
    if(xhr.status >=200 && xhr.status <300||xhr.status==304){
        
    }
}
xhr.open('get','test/a/b',true)
xhr.setRequestHeader('MyHeader','MyValue');
xhr.send(null)

GET请求

xhr.open('get','example.php?name=value&name2=value2',true)
url +="?"+encodeURIComponent(name)+"="+encodeURIComponent(value);
return url;

POST 请求

var xhr = createXHR();
//利用dom0级方法为xhr对象添加事件处理程序
xhr.onreadystatechange = function(){
    if(xhr.status >=200 && xhr.status <300||xhr.status==304){
        
    }
}
xhr.open('post','test/a/b',true)
xhr.setRequestHeader('MyHeader','MyValue');
xhr.send(serialize({'d':'ab'}))

XMLHttpRequest2

FormData

var xhr = createXHR();
//利用dom0级方法为xhr对象添加事件处理程序
xhr.onreadystatechange = function(){
    if(xhr.status >=200 && xhr.status <300||xhr.status==304){
        
    }
}
xhr.open('post','test/a/b',true)
xhr.setRequestHeader('MyHeader','MyValue');
var data = new FormData();
data.append('name','Nic')
xhr.send(data)

超时限定

var xhr = createXHR();
//利用dom0级方法为xhr对象添加事件处理程序
xhr.onreadystatechange = function(){
    if(xhr.status >=200 && xhr.status <300||xhr.status==304){
        
    }
}
xhr.open('post','test/a/b',true)
xhr.setRequestHeader('MyHeader','MyValue');
var data = new FormData();
xhr.timeout=1000;//1秒
xhr.ontimeout = function(){
    console.log('d')
}
data.append('name','Nic')
xhr.send(data)

进度事件

Progress Events定义了与客户端服务器通信有关的事件

  • loadStart 接收响应数据的第一个字节触发
  • progress 接收响应期间持续不断触发
  • error 请求发生错误触发
  • abort abort()方法而终止连接时触发
  • load 接收完整响应数据时触发
  • loadend 在通信完成或者触发error, abort, load事件后触发

progress事件

xhr.onprogress 在浏览器接收新的数据据期间周期性的触发

#服务器向页面推送数据的技术

Comet

一种更高级的Ajax技术

也称服务器推送

一种服务器向页面推送数据的技术

能够让信息实时地推送到页面。适合处理体育比赛,股票报价

两种实现方式

  • 长轮询

长轮询

浏览器定时向服务器发送请求,看有咩有更新数据

过程和短轮询(请求,马上响应)不一样

过程:

  • 页面发送一个服务器请求
  • 服务器一直保持连接打开,直到有数据可发送
  • 发送完数据之后,浏览器关闭连接
  • 重复

使用XHR对象,和setTimeout就能实现

HTTP流

整个生命周期内只使用一个HTTP连接

浏览器向服务器发送一个请求,服务器保持连接打开,然后周期性地向浏览器发送数据

  • readyState值,会周期性地变为3,responseText属性中就会保存接收到所有的数据
function createStreamingClient(url,progress,fininsed){
    var xhr = new XMLHttpRequest(),received =0;
    xhr.open('get',url,true);
    xhr.onreadystatechange = function(){
        var result;
        if(xhr.readyState ===3){
            //取得最新数据并调整计数器
            result = xhr.responseText.substring(received);
            received = += result.length;
            //调用progress回调
            progress(result);
        }else if  (xhr.readyState===4){
            fininshed(xhr.responseText)
        }
    }
}
var client = createStreamingClient('streaming.php',function(data){
    console.log(data)
}),function(data){
    console.log(data)
}

浏览器设区简化Comet技术,创建两个新的接口

SSE(server sent events, 服务器发送事件)

围绕只读的Comet交互推出的API或者模式

  • 用于创建服务器的单向连接,服务器可以通过一个连接发送任意数量的数据。
  • 服务器响应的MIME类型必须是text/event-stream
  • 支持短轮询,长轮询,HTTP流
  • 断开连接时,决定何时重新连接
  • 适合长轮询,和http流
  • 断开不重连,使用close()方法
//传入一个入口点, 需要与创建对象的页面同源, 相同的url模式,域,端口
var source = new EventSource('myevents.php')
//- open 在建立连接时触发
//- message: 从服务器接收到新事件时触发
//- error: 在无法建立连接时触发
source.onmessage = function(event){
    var data = event.data;
    //处理数据
}

事件流,响应格式是纯文本

Web Sockets (重点)

  • 全双工
  • 双向通信

流程:

  • javascript创建了 Web Socket之后,会有一个HTTP请求发送到(浏览器 有疑惑)以发送连接

  • 取得服务器响应后,建立的连接后从HTTP 升级到WebSocket协议

  • 未加密 ws://, 加密: wss://

  • 适合移动应用

  • readyState属性,表示当前状态

    • WebSocket.OPENING(0) 正在建立连接
    • OPEN(1):已经建立连接
    • CLOSING(2):正在关闭连接
    • CLOSE(3) 已经关闭连接
  • 关闭,socket.close()

  • 其他事件

    • open

    • error

    • close

var socket = new WebSocket('ws://www.example.com/server.php');
//发送数据,纯文本
socket.send('hello world')
socket.send(JSON.stringify({'a':'b'}))
//接收
socket.onmessage = function(event){
    var data = event.data;
   //处理数据
}
socket.onopen = function(){}
socket.onerror = function(){
    
}
socket.onclose = function(){
    
}

安全

确保XHR,访问url 安全, 验证发送者是否有权限访问相应的资源

  • ssl 连接访问
  • 签名
  • cookie验证
  • 检测url是否可信

跨域源资源共享

通过XHR 实现Ajax通信的一个主要限制,跨域安全策略。 XHR对象只能访问与包含它的页面位于同一个域中的资源

CORS 是w3c的一个工作草案,定义了浏览器与服务器应该如何沟通。cors的背后基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败

  1. http get /post 请求

  2. 添加Origin: www.nczoline.net

  3. 服务器认为这个请求可以接受,添加Access-Control-Allow-Origin头部,内容 www.nczoline.net

IE对CORS的实现

xdr 类型,这个对象与XHR类似

  • cookie不会随请求发送,也不会随响应返回
  • 只能设置请求头部信息中的Content-Type字段
  • 不能访问响应头部的信息
  • 只支持get. post请求
  • 请求都是异步执行的,请求返回触发load事件,响应数据保存在reponseText
  • 无法确定响应的状态码
  • onerror事件处理请求失败

缓解:

csrf cross-site request forgery 跨站点请求伪造

xss cross-siet scripting 跨站点脚本

Prefighted Requests

CORS 通过一种叫做Preflighted Requests的透明服务器验证机制,支持开发人员自定义头部

  • Origin : www.ncz.net

  • Access-Control-Allow-Methods:POST,运行的方法

  • Access-Control-Allow-Headers:NCZ

  • Access-Control-Max-Age:172800缓存的时间

  • Access-Control-Allow-Credentials: true ,默认跨域请求不提供凭据,来设置这个来,要求提供凭据

实现跨浏览器的cors

1.检查是否存在withCredentials属性

2.检测XDomainRequest对象是否存在

function createCORSRequest(method,url){
    var xhr = new XHLHttpRequest();
    if('withCredentias' in xhr){
        xhr.open(method,url,true)
    }else if(typeof XDomainRequest !="undefined"){
        xhr=new XDomainRequest();
        xhr.open(method,url)
    }else{
        xhr = null;
    }
    return xhr;
}
var request = createCORSRequest('get','http://www.somewhere-else.com/page/');
if(request){
    request.onload = function(){
        //对request.responseText进行处理
    };
    request.send();
}

其他跨域技术

图像Ping 常用于跟踪用户点击页面或动态广告曝光次数

  • 只能发送get
  • 无法访问服务器响应脚本
  • 浏览器向服务器的单向通信
var img = new Image();
img.onload = imge.onerror = function(){
    ...
}
img.src='http://www.example.com/test?name=N'

JSONP

  • 能直接访问响应脚本

  • 双向通信

  • 其他域不安全,会夹带恶意代码

JSON width padding 填充式JSON 或参数式JSON

callback({'name':'Nicholas'})

由回调函数和数据组成

回调函数是响应到来时页面应该调用的函数

JSONP请求:freegeip.net/json/?callb…

function handleReponse(response){
    console.log('ddd')
}