精华内容
下载资源
问答
  • 什么是同步请求和异步请求
    千次阅读 多人点赞
    2020-07-20 08:32:37

    一、同步、异步请求
    浏览器发送请求给服务器,其有同步请求和异步请求两种方式。

    1同步请求

    什么叫同步请求呢?

    就是在发送一个请求之后,需要等待服务器响应返回,才能够发送下一个请求。

    之前学的请求是通过浏览器地址栏发送请求,这种方式就是属于同步请求。

    但是其有两个缺陷:

    ①请求必须要等待响应

    如果遇到请求阻塞,网络延迟,用户需要等待,这样用户体验效果不好。

    ②请求时会携带所有的信息

    比如说一个form表单,需要填入用户名,密码,手机号,等多个信息。

    如果其中有一个信息填写错了,请求失败,又要全部重新填写,会很麻烦繁琐。

    我只填写我填错了的不就好了么?

    如何解决这个问题?就需要引入异步的概念了。

    2异步请求

    和同步请求相对,异步不需要等待响应,随时可以发送下一次请求。

    如果是同步请求,需要将信息填写完整,再发送请求,服务器响应填写是否正确,再做修改。

    但是异步请求是局部页面更新。

    比如上述的手机号、密码,邮箱名,在填写时就会发送一个异步请求。

    若是格式不正确,会提醒修改,而其它已经填写的正确信息不受影响。

    二、原生的Ajax
    什么叫Ajax呢?

    说白了就是用来发送异步请求的一种方式。

    先写一个异步请求案例,再逐步学习。

    有一个按钮,给它注册个点击事件,点击就发送异步请求,其具体实现方式共五步:

    ①创建

    是AJAX的基础。

    Ajax就是通过这个对象来发送异步请求的。

    ②onreadystatechange事件

    不要看这一大串这么长,翻译过来就是当前数据源的数据将要发生变化时,就可以理解成监听。

    这个事件就是实现异步请求的核心关键。

    为什么异步请求可以不用等待响应?

    就是因为这儿设置了一个监听事件。

    服务器被监听,一旦readyState为4并且status为200,表明响应成功。

    这些属性都是怎么来的,w3c文档中就有说明:

    readyState和status都对应有不同的数值,只不过4和200表示响应成功。

    ③绑定提交地址

    open()方法,其有三个参数:

    method:即请求方式,例子中是GET请求。
    url:请求路径,"/getAjaxServlet"。
    async:true表示为异步、false表示为同步,不写默认为true。
    ④发送请求

    send()方法,将请求发送到服务器。

    同样的道理,这些方法在w3c文档中也有详细说明。

    ⑤接收响应数据

    也就是在②中判断响应成功时,接受响应的数据,有两种属性:

    responseText :获取字符串形式的数据。
    responseXML:获取XML形式的数据。
    如果不是XML数据,都使用responseText。

    以上就是原生的Ajax,当然实际使用过程中不会这样用,但是面试时可能会被问到。

    并且这是基础,学一下也是有必要的。

    三、JSON
    JSON是一种轻量级的数据交换格式,具有良好的可读性以及便于编写。

    在JSON之前一般都是使用xml来传递数据的,将这两种数据格式做一个对比:

    相比较而言:json数据更加地简洁。

    当然XML也并不是一无是处,其格式统一,就观感而言也有人更喜欢xml这种排版方式。

    并且XML出来了很久了,推广深入人心,通用性高,喜欢XML的人还是挺多的。

    但是对于传输数据来说,数据是否容易被解析?这是非常重要的。

    而json相对于xml而言就具有这样的优势,故在这一块更加地常用。

    Json的基础语法

    一共有三种数据格式,分别说明:

    ①对象类型

    格式为:{name:value,name:value……}

    以键值对的方式存储数据,可以有多个键值对,键值对之间用逗号隔开。

    其中name为字符串类型,而value是任意类型。

    ②数组/集合类型

    格式为:[value,value…]

    其中value是任意类型。

    和数组就很类似,只不过是使用中括号将数据包裹起来的。

    ③混合类型

    即包含对象类型和数组类型。

    值得注意的是:

    JSON数据的key值:字符串类型,必须加双引号。
    JSON数据的value值:任意类型,如果是字符串则必须加双引号。
    时间有限,其中关于json还有一些api就不做专门讲解了,今后使用到了边记边学就好了。

    更多相关内容
  • js代码-简单异步请求重试
  • 在项目中,经常会遇到多个相互依赖的异步请求。如有a,b,c三个ajax请求,b需要依赖a返回的数据,c又需要a和b请求返回的数据。如果采用请求嵌套请求的方式自然是不可取的。导致代码难以维护,如何请求很多。会出现很多...
  • JavaScript中的如何解决异步请求 想必有过项目经验的小伙伴,都对异步请求不陌生。今天小编就带大家来说说什么是异步请求以及如何解决? 一、常见的异步请求(数据请求) 1.XMLHttpRequest js异步请求 2.$.ajax ...

    JavaScript中的如何解决异步请求

    想必有过项目经验的小伙伴,都对异步请求不陌生。今天小编就带大家来说说什么是异步请求以及如何解决?

    一、常见的异步请求方法(数据请求)

    1.XMLHttpRequest js异步请求

    2.$.ajax jquery异步方法

    3.axios (很多公司使用的异步请求库
      Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
      官方文档:https://www.kancloud.cn/yunye/axios/234845

    4.promise是es6里用来解决回调地狱的方案,主要作用是让代码换了个书写形式,由异步形式换成可读性更好的“同步”形式。

    5.es7中的async,await同理

    • async 表示这是一个async函数,await只能用在这个函数里面。
    • await 表示在这里等待promise返回结果了,再继续执行。
    • await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)

    6.fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。

    二、解决异步请求的发展及优缺点

    1. 回调函数(callback)
     setTimeout(() => {
                console.log('settimeout');
            }, 1000);
            console.log(1);
    
            
            $.ajax({
                url:'',
                success(){
                    $.ajax({
                        url:'',
                        success(){
                            $.ajax({
                                url:'..'
                            })
                        }
                    })
                }
            })
    
            
    

    试想,如果再多几个异步函数,代码整体的维护性,可读性都变的极差,如果出了bug,修复的排查过程也变的极为困难,这个便是所谓的 回调函数地狱

      优点: 解决了同步问题(解决了  只要有一个任务耗时间很长,后面的任务必须排队进行执行,会延迟严重。)
      缺点:回调地狱,不能用 try catch 捕获错误,不能return
    
    1. Promise

    Promise是解决异步回调的ES语法的标准,通常用来解决异步嵌套和多异步同时完成回调等问题。我的理解就是:在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。

    Promise是一个构造函数,相当于一个容器,把异步代码包裹在里面,promise有三个状态(pending(进行中)、fulfilled(已成功)和rejected(已失败)),初始化为pending,当异步请求成功后调用resolve函数,状态从pending—>fulfilled,失败的时候调用reject,状态从pending—>rejected。状态不可逆。

    Promise的几种方法:

            (1)、Promise.prototype.then()
            then方法是定义在原型对象Promise.prototype上的,他的作用是为Promise实例添加状态 改变是的回调函数。
            then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。为宏任务中的微任务。
            (2)、Promise.prototype.catch()
            此方法是.then(null,rejection)的别名,用于指定错误发生时的回调函数。
            (3)、Promise.all()
            此方法用于将多个Promise实例包装成一个新的promise实例。
            (4)、Promise.race()
            也是将多个Promise实例包装成一个新的promise实例。
            (5)、Promise.resolve()
            将现有对象转换为Promise对象
            (6)、Promise.reject()
            Promise.reject(reason)方法返回一个状态为Rejected的新Promise实例。
    

    有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

    下面是promise的基本用法:

    const promise = new Promise(function (resolve, reject) {
                // ... some code
                if (/* 异步操作成功 */) {
                    resolve(value);
                } else {
                    reject(error);
                }
            }).then(function (value) {
                // success
            }, function (error) {
                // failure
            });
    

    简单案例1:

     function timeout(ms) {
            return new Promise((resolve, reject) => {
                setTimeout(resolve, ms, 'done');
                // resolve('done')
            });
        }
    
        timeout(100).then((value) => {
            console.log(value); //done
        });
    

    上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数。

    简单案例2:

    let promise = new Promise(function(resolve, reject) {
      console.log('Promise');
      resolve();
    });
    
    promise.then(function() {
      console.log('resolved.');
    });
    
    console.log('Hi!');
    
    // Promise
    // Hi!
    // resolved
    

    上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数, 将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

    简单案例3:

    function loadImageAsync(url) {
                return new Promise(function (resolve, reject) {
                    const image = new Image();
    
                    image.onload = function () {
                        resolve(image);
                    };
    
                    image.onerror = function () {
                        reject(new Error('Could not load image at ' + url));
                    };
    
                    image.src = url;
                });
            }
    

    上面代码中,使用Promise包装了一个图片加载的异步操作。如果加载成功,就调用resolve方法,否则就调用reject方法。

    简单案例4.

    下面是一个用Promise对象实现的 Ajax 操作的例子。

    const getJSON = function (url) {
                const promise = new Promise(function (resolve, reject) {
                    const handler = function () {
                        if (this.readyState !== 4) {
                            return;
                        }
                        if (this.status === 200) {
                            resolve(this.response);
                        } else {
                            reject(new Error(this.statusText));
                        }
                    };
                    const client = new XMLHttpRequest();
                    client.open("GET", url);
                    client.onreadystatechange = handler;
                    client.responseType = "json";
                    client.setRequestHeader("Accept", "application/json");
                    client.send();
    
                });
    
                return promise;
            };
    
            getJSON("/posts.json").then(function (json) {
                console.log('Contents: ' + json);
            }, function (error) {
                console.error('出错了', error);
            });
    

    上面代码中,getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。


    Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    优点: 解决回调地狱
    缺点: 无法取消promise ,错误需要通过回调函数获取 ,书写麻烦,不能实现异步代码,同步执行的需求(配合async函数使用即可)

    可详细学习: https://es6.ruanyifeng.com/#docs/promise

    3、 generator

        特点:可以控制函数的执行,可以配合 co 函数库使用
    

    4、 async/await

    async/await 是异步的终极解决方案。
    要注意的是,await只能在函数中用async关键字标记后才能使用
    1、async 表示这是一个async函数,await只能用在这个函数里面。
    2、await 表示在这里等待promise返回结果了,再继续执行。
    3、await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)

                Async函数表示函数里面可能会有异步方法,并且函数返回的是promise对象。遇到await会立即执行await表达式,然后再将其后的代码放入到微任务中,让出执行站让同步代码先执行。
    

    下面再带领大家看一些面试中常出现的异步代码题:

    1. promise
     	console.log(0)
        new Promise(function(res,rej){
            console.log(1);
            // res()
            // rej()
        }).then(function(){
            console.log('then');
        }).catch(function(){
            console.log('catch');
        })
        console.log(3);
    

    2.async/await

    async function show(){
            console.log(1);
            await dev() // await 后面的代码为异步微任务代码
            console.log(2);
        }
        function dev(){
            console.log('await');
        }
        console.log('first');
        show()
    

    3.综合练习

     async function async1(){
            console.log('async1 start');
            await async2();
            console.log('async1 end');
        }
    
        async function async2(){
            console.log('async2');
        }
    
        console.log('script start');
    
        setTimeout(function(){
            console.log('settimeout');
        },0)
    
        async1();
    
        new Promise(function(resolve){
            console.log('promise1');
            resolve()
        }).then(function(){
            console.log('promise2');
        })
    
        console.log('script end');
    
        //打印:script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> settimeout
    

    文章最后,感谢大家的观看,祝大家学有所成!

    展开全文
  • 完美解决ie9 ajax 请求失败问题,解决ie9 跨域请求失败问题,欢迎下载,亲测有效。jquery.XDomainRequest.js
  • axios实现异步请求

    千次阅读 2021-10-21 21:16:41
    Vuejs 并没有直接处理ajax的组件,但可以使用axios或vue-resource组件实现对异步请求的操作。 使用axios或vue-resource组件实现对异步请求的操作。 vue-resource vue-resource是Vue.js的插件提供了使用...

    ajax

    Vuejs 并没有直接处理ajax的组件,但可以使用axios或vue-resource组件实现对异步请求的操作。

    使用axiosvue-resource组件实现对异步请求的操作。

    vue-resource

    vue-resource是Vue.js的插件提供了使用XMLHttpRequest或JSONP进行Web请求和处理响应的服务。 当vue更新到2.0之后,作者就宣告不再对vue-resource更新,而是推荐axios。

    axios

    Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

    axios的github地址:https://github.com/axios/axios

    # 如果使用npm则可以如下安装
    npm install axios
    

    或者也可以直接使用公共的CDN(内容分发网络)服务:

    <!-- 开发环境版本,包含了用帮助的命令行警告 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    

    axios的作用

    1. 发送异步请求获取数据

    2. 常见的方法:

      1. get、post

        常用的就是get和post

      2. 在发送的时候可以指定参数(地址、请求方式和请求头部信息);

      3. 返回数据结构(data/status/statusText/headers/config)

        data返回的数据都在这个里面

    方法说明

    config请求配置

    这些是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method ,请求将默认使用 get 方法。

    {
    	// `url` 是用于请求的服务器 URL
    	url: '/user',
    
        // `method` 是创建请求时使用的方法
    	method: 'get', // 默认是 get
    
            
        // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
    	// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
    	baseURL: 'https://some-domain.com/api/',
    
            
        // `transformRequest` 允许在向服务器发送前,修改请求数据
    	// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
    	// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
    	transformRequest: [function (data) {
    		// 对 data 进行任意转换处理
    		return data;
    	}],
    	
        // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
    	transformResponse: [function (data) {
    		// 对 data 进行任意转换处理
    		return data;
    	}],
    
            // `headers` 是即将被发送的自定义请求头
    
            headers: {
    			'X-Requested-With': 'XMLHttpRequest',
    			'Content-Type': 'application/json'
    		},
    
         // `params` 是即将与请求一起发送的 URL 参数
    	// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
    	params: {
    		ID: 12345
    	},
    
        
        // `data` 是作为请求主体被发送的数据
    
        // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
    
        // 在没有设置 `transformRequest` 时,必须是以下类型之一:
    
        // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
    
        // - 浏览器专属:FormData, File, Blob
    
        // - Node 专属: Stream
    	data: {
    		firstName: 'Fred'
    	},
    
        
        // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
    	// 如果请求话费了超过 `timeout` 的时间,请求将被中断
    	timeout: 1000,
    
        
        // `withCredentials` 表示跨域请求时是否需要使用凭证
    	withCredentials: false, // 默认的
    
        // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document',
    'json', 'text', 'stream'
    	responseType: 'json', // 默认的
    
        // `maxContentLength` 定义允许的响应内容的最大尺寸
    	maxContentLength: 2000,
    
        // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果`validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
    
        validateStatus: function (status) {
    		return status >= 200 && status < 300; // 默认的
    	},
    
    // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
    // 如果设置为0,将不会 follow 任何重定向
    	maxRedirects: 5 // 默认的
    }
    

    响应结构

    {
    	// `data` 由服务器提供的响应
    	data: {},
    	// `status` 来自服务器响应的 HTTP 状态码
        status: 200,
    	// `statusText` 来自服务器响应的 HTTP 状态信息
    	statusText: 'OK',
    	// `headers` 服务器响应的头
    	headers: {},
    	// `config` 是为请求提供的配置信息
    	config: {}
    }
    

    axios方法

    不能以静态文件去访问数据,这样会报错;需要以服务器的方式去访问才不会报错

    • 在这里演示的是静态的一个json文件,访问是服务器地址也是可以的,这三种方式(axios、get和post方法)都可以,做法也是一模一样

      注意:如果使用axios访问跨域数据的时候,只需要在服务提供方中,在方法上面使用SpringMVC的跨域注解即可解决数据跨域问题。如在方法上添加:@CrossOrigin(origins = “http://localhost:10000”)
      如果请求的地址是使用了网关,那么在网关服务器上配置跨域就可以了;不能同时在网关服务器和服务提供服务工程中同时配置。

      跨域:在前端js中如果发送异步请求的话,请求的地址与当前服务器的ip或者端口号不同都是跨域请求,可以使用如下方式在服务器端进行配置:

      image-20211021211539039

    • 测试代码:

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>测试</title>
          <script src="node_modules/vue/dist/vue.js"></script>
          <script src="js/axios.min.js"></script>
      </head>
      <body>
          <div id="va">
              <ul>
                  <li v-for="(user,index) in users" :key="index">
                      {{index}}--{{user.name}}--{{user.age}}--{{user.gender}}
                  </li>
              </ul>
          </div>
      <script>
          //父组件
          var va = new Vue({//创建一个vue实例
              el:"#va",//el即element,要渲染的页面元素
              data: {
                  users:[]
              },
              //使用钩子函数初始化加载数据
              created(){
                  //加载数据
                  axios({
                      method:"get",
                      url: "data.json"
                  }).then((res)=>{//加载数据成功,在这个{}里面对res数据进行处理
                      console.log(res);
                      //将数据赋值到vue实例中的数据属性users
                      //不能使用this,this在axios回调函数中表示的是窗口,不是vue实例
                      va.users = res.data;
                  }).catch(error=>{//加载数据失败
                      alert(error);//失败就弹出数据
                  });
              }
          });
      </script>
      </body>
      </html>
      
    • data.json的数据内容:

      [
        {"name":"张三","age":8,"gender":"男"},
        {"name":"李四","age":12,"gender":"女"},
        {"name":"王五","age":4,"gender":"男"}
      ]
      
    • 效果1:使用静态文件去访问,会报错,按shift打开

      image-20211021210614765

    • 效果2:直接打开,这样是使用服务器去打开,这样不会错误

      image-20211021210656790

    get方法

    示例中的axios操作部分修改为如下,

    • 就修改了下面的这些代码,
    • 最后的实现效果一样
    axios.get("data.json").then((res)=>{//加载数据成功,在这个{}里面对res数据进行处理
        console.log(res);
        //将数据赋值到vue实例中的数据属性users
        //不能使用this,this在axios回调函数中表示的是窗口,不是vue实例
        va.users = res.data;
    }).catch(error=>{//加载数据失败
        alert(error);//失败就弹出数据
    });
    

    post方法

    示例中的axios操作部分修改为如下,

    • 就修改了下面的这些代码,
    • 最后的实现效果一样
    axios.post("data.json").then((res)=>{//加载数据成功,在这个{}里面对res数据进行处理
        console.log(res);
        //将数据赋值到vue实例中的数据属性users
        //不能使用this,this在axios回调函数中表示的是窗口,不是vue实例
        va.users = res.data;
    }).catch(error=>{//加载数据失败
        alert(error);//失败就弹出数据
    });
    
    展开全文
  • 异步请求的方法

    千次阅读 2021-04-29 14:24:52
    AJAX ( Asynchronous JavaScript and XML ) 异步的 JS 和 XML,通过 AJAX 可以在浏览器中向服务器发送异步请求,核心是XMLHttpRequest。 无需刷新页面获取数据 根据用户事件来更新页面部分内容 1.1. ...

    1. AJAX

    AJAX ( Asynchronous JavaScript and XML ) 异步的 JS 和 XML,通过 AJAX 可以在浏览器中向服务器发送异步请求,核心是XMLHttpRequest。

    1. 无需刷新页面获取数据
    2. 根据用户事件来更新页面部分内容

    1.1. XMLHttpRequest 中基本的方法有

    • abort() : 停止发送当前请求
    • getAllResponseHeaders() : 获取服务器返回的全部响应头
    • getRequestHeader(“headerLabel”):根据指定的请求头, 获取相应的值
    • open( “method” , “url” [ , asyncFlag , “uname” , “passwd” ] ):建立与服务器 URL 的链接并设置请求的方法以及是否使用异步请求(默认为支持异步请求)
    • asyncFlag 处的为 true 表示支持异步请求, false 表示不支持。如果远程链接需要用户名和密码, 则可以在参数中提供。
    • send( content ) : 发送请求 ( 其中 content 是请求参数)
    • setRequestHeader( “label” , “value” ):发送请求之前, 先设置请求报头

    1.2. XMLHttpRequest 中的常用属性

    • onreadystatechange:用于指定 XMLHttpRequest 对象状态改变时对应的时间处理函数
    • readyState:XMLHttpRequest 对象的处理状态
    • responseText:该属性用于获取服务器的响应文本
    • responseXML:该属性用于获取服务器响应的XML文档对象
    • status:对应服务器返回的状态代码(只有当服务器的响应完成时, 才会有该状态代码)
    • statusText : 对应服务器返回的状态文本信息(当服务器响应完成时)
    • onreadystatechange 属性 :用于指定一个函数 ,这个函数负责处理 XMLHttpRequest 状态变化时的事件
    • readyState 属性 : 对应 XMLHttpRequest 对象的状态。XMLHttpRequest 的状态有
      • 0 : 表示 XMLHttpRequest 对象还没有完成初始化
      • 1 : 表示 XMLHttpRequest 对象开始发送请求
      • 2 : 表示 XMLHttpRequest 对象请求发送完成
      • 3 : 表示 XMLHttpRequest 对象开始读取服务器响应信息
      • 4 : 表示 XMLHttpRequest 对象读取服务器响应结束
    • status 属性 : 对应服务器响应代码, 用于判断服务器响应是否正确
    • statusText 属性:用于获取服务器响应码对应的响应信息。 无论响应代码是什么, 只要生成了响应, 就可以获取响应信息。
    • responseText 属性:获取服务器发送来的文本信息(如果服务器发送的是文本信息)。异步数据传输中, JSON 格式的数据通常使用该属性获取
    • responseXML 属性 : 如果服务器响应发送的是 XML 格式的数据, 用该属性获取。(早期的 AJAX 应用中, 传输的数据都是 XML 格式的)

    1.3. 使用XMLHttpRequest进行异步通信的步骤

    • 初始化 XMLHttpRequest 对象 : 视不同浏览器创建 XMLHttpRequest 对象

    • 打开与服务器的连接 : 使用 open() 方法开启连接

    • 设置监听 XMLHttpRequest 状态改变的事件处理函数。可以在 onreadystatechange 之后直接书写函数,也可以单独书写函数, 然后在这里指定函数名即可。

    • 设置请求报头。一般要设置跟当前请求有关的报头, 比如编码等。使用 setRequestHeader() 方法设定

    • 发送请求。向服务器发请求,如果是 POST 请求, 可以发送参数, 否则发送 null 即可。

    • // AJAX基础步骤
      
      // 1. 创建 xhrHttpRequest 对象
      let xhr;
      if (window.xhrRequest) {
      	// code for IE7+, Firefox, Chrome, Opera, Safari
      	xhr = new xhrHttpRequest();
      } else {
      	// code for IE6, IE5
      	xhr = new ActiveXObject("Microsoft.xhr");
      }
      // 设置JSON格式自动转换
      xhr.responseType='json';
      
      // 2. 设置请求方法和url
      // GET请求
      xhr.open("GET", "http://127.0.0.1:3300/server?name=zs&password=123", true);
      
      // POST请求
      // xhr.open('POST','http://127.0.0.1:3300/server')
      // xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
      // xhr.send(param) post请求参数放在 send 方法中
      
      // 3. 发送
      xhr.send();
      // 4.事件绑定 处理服务端返回的结果
      xhr.onreadystatechange = function () {
      	if (xhr.readyState == 4) {
      		if (xhr.status >= 200 && xhr.status < 300) {
                  // 手动转换 JSON 数据转为JS对象 JSON.parse(xhr.response)
      			console.log(xhr.status); // 状态码
      			console.log(xhr.statusText); // 状态字符串
      			console.log(xhr.getAllResponseHeaders()); // 所有响应头
      			console.log(xhr.response); // 响应体
      		}
      	}
      };
      
      
    • // 引入express模块
      const express = require('express')
      // 创建应用对象
      const app = express()
      const port = 3000
      
      // 创建路由规则
      // req 对请求报文的封装
      // res 对响应报文的封装
      app.get('/', (req, res) => {
          // JSON格式 JSON.stringify(data)
        res.send('Hello World!')
      })
      
      // 如果参数值中有中文,比如张三丰,则用encodeURI对中文进行编码 data = "username="+encodeURI("张三丰")+"&password=2016";
      
      // app.post("/", function (req, res) {
      // 	res.send("POST request to the homepage");
      // });
      
      // app.all("/secret", function (req, res, next) {
      // 设置响应头,允许跨域
      	response.setHeader('Access-Control-Allow-Origin','*');
      // 允许任何类型的请求头
      	response.setHeader('Access-Control-Allow-Headers','*')
      // 	console.log("Accessing the secret section ...");
      // 	next(); // pass control to the next handler
      // });
      
      // 监听端口启动服务
      app.listen(port, () => {
        console.log(`Example app listening at http://localhost:${port}`)
      })
      

    1.4. nodemon

    修改服务器代码后,自动重启的一个工具,nodemon server.js

    1.5. AJAX-IE 缓存问题

    // 解决 IE 缓存
    xhr.open("GET",'http://127.0.0.1:3300/ie?t='+Date.now())
    

    1.6. 请求超时与网络异常

    // 超时设置 2s
    xhr.timeout=2000;
    // 超时回调
    xhe.ontimeout = function(){}
    // 服务器设置定时器
    
    // 网络异常回调
    xhr.onerror = function(){}
    

    1.7. 取消请求

    // 停止发送当前请求
    xhr.abort()
    

    1.8. 重复发送请求

    let x =null;
    let isSending = false; // 是否正在发送AJAX请求
    
    if(isSending){
    	x.abort(); //如果正在发送,则取消该请求,创建一个新的请求
    }
    x= new XMLHTTPRequest();
    isSending = true;
    
    xhr.open("GET", "http://127.0.0.1:3300/delay", true);
    
    x.send();
    // 4.事件绑定 处理服务端返回的结果
    x.onreadystatechange = function () {
    	if (x.readyState == 4) {
            isSending = false;
    	}
    };
    
    

    1.9. 模仿JQuery ajax()方法封装函数

    function ajax(obj){
        // 默认参数
        let defaults = {
            type : 'get',
            data : {},
            url : '#',
            dataType : 'text',
            async : true,
            success : function(data){console.log(data)}
        }
        // 处理形参,传递参数的时候就覆盖默认参数,不传递就使用默认参数
        for(let key in obj){
            defaults[key] = obj[key];
        }
        // 1、创建XMLHttpRequest对象
        let xhr = null;
        if(window.XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }
        // 把对象形式的参数转化为字符串形式的参数
        /*
        {username:'zhangsan','password':123}
        转换为
        username=zhangsan&password=123
        */
        let param = '';
        for(let attr in defaults.data){
            param += attr + '=' + defaults.data[attr] + '&';
        }
        if(param){
            param = param.substring(0,param.length - 1);
        }
        // 处理get请求参数并且处理中文乱码问题
        if(defaults.type == 'get'){
            defaults.url += '?' + encodeURI(param);
        }
        // 2、准备发送(设置发送的参数)
        xhr.open(defaults.type,defaults.url,defaults.async);
        // 处理post请求参数并且设置请求头信息(必须设置)
        let data = null;
        if(defaults.type == 'post'){
            data = param;
            xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        }
        // 3、执行发送动作
        xhr.send(data);
        // 处理同步请求,不会调用回调函数
        if(!defaults.async){
            if(defaults.dataType == 'json'){
                return JSON.parse(xhr.responseText);
            }else{
                return xhr.responseText;
            }
        }
        // 4、指定回调函数(处理服务器响应数据)
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                if(xhr.status == 200){
                    let data = xhr.responseText;
                    if(defaults.dataType == 'json'){
                        // data = eval("("+ data +")");
                        data = JSON.parse(data);
                    }
                    defaults.success(data);
                }
            }
        }
    }
    
    

    2. JQuery Ajax()

    2.1. get 请求

    $.get(url, [data], [callback], [type])

    1. url:请求的 URL 地址。
    2. data:请求携带的参数。
    3. callback:载入成功时回调函数。
    4. type:设置返回内容格式,xml, html, script, json, text, _default。

    2.2. post 请求

    $.post(url, [data], [callback], [type])

    1. url:请求的 URL 地址。
    2. data:请求携带的参数。
    3. callback:载入成功时回调函数。
    4. type:设置返回内容格式,xml, html, script, json, text, _default。

    2.3. 通用方法

    $.ajax({
        // url
    	url: 'http://127.0.0.1:3300/jquery-server',
        // 参数
        data: {a:1, b:2},
        // 请求类型
        type: 'GET',
        // 响应体结果类型
        dataType: 'json'
        // 成功的回调
        success: function(data){
            console.log(data);
        },
        // 超时时间
        timeout: 2000,
        error: function(error){
            console.log(error);
        },
        // 头信息
        headers: {
            c:300,
            d:400
        }
    })
    

    3. Axios

    Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

    3.1. GET请求

    // 为给定 ID 的 user 创建请求
    axios.get('/user?ID=12345')
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });
    
    // 上面的请求也可以这样做
    axios.get('/user', {
        params: {
          ID: 12345
        }
      })
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });
    

    3.2. POST请求

    axios.post('/user', {
        firstName: 'Fred',
        lastName: 'Flintstone'
      })
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });
    

    3.3. 并发请求

    // 处理并发请求的助手函数
    // axios.all(iterable)
    // axios.spread(callback)
    
    function getUserAccount() {
      return axios.get('/user/12345');
    }
    
    function getUserPermissions() {
      return axios.get('/user/12345/permissions');
    }
    
    axios.all([getUserAccount(), getUserPermissions()])
      .then(axios.spread(function (acct, perms) {
        // 两个请求现在都执行完成
      }));
    

    3.4. 通用方法

    // 发送 GET 请求(默认的方法)
    axios('/user/12345');
    
    // 发送 POST 请求
    axios({
      method: 'post',
      url: '/user/12345',
      data: {
        firstName: 'Fred',
        lastName: 'Flintstone'
      }
    });
    
    // 获取远端图片
    axios({
      method:'get',
      url:'http://bit.ly/2mTM3nY',
      responseType:'stream'
    })
      .then(function(response) {
      response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
    });
    

    3.5. 请求方法别名

    • axios.request(config)
    • axios.get(url[, config])
    • axios.delete(url[, config])
    • axios.head(url[, config])
    • axios.options(url[, config])
    • axios.post(url[, data[, config]])
    • axios.put(url[, data[, config]])
    • axios.patch(url[, data[, config]])
    3.5.1. 注意

    在使用别名方法时, urlmethoddata 这些属性都不必在配置中指定。

    3.6. 请求配置

    这些是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。

    {
       // `url` 是用于请求的服务器 URL
      url: '/user',
    
      // `method` 是创建请求时使用的方法
      method: 'get', // default
    
      // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
      // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
      baseURL: 'https://some-domain.com/api/',
    
      // `transformRequest` 允许在向服务器发送前,修改请求数据
      // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
      // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
      transformRequest: [function (data, headers) {
        // 对 data 进行任意转换处理
        return data;
      }],
    
      // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
      transformResponse: [function (data) {
        // 对 data 进行任意转换处理
        return data;
      }],
    
      // `headers` 是即将被发送的自定义请求头
      headers: {'X-Requested-With': 'XMLHttpRequest'},
    
      // `params` 是即将与请求一起发送的 URL 参数
      // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
      params: {
        ID: 12345
      },
    
       // `paramsSerializer` 是一个负责 `params` 序列化的函数
      // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
      paramsSerializer: function(params) {
        return Qs.stringify(params, {arrayFormat: 'brackets'})
      },
    
      // `data` 是作为请求主体被发送的数据
      // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
      // 在没有设置 `transformRequest` 时,必须是以下类型之一:
      // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
      // - 浏览器专属:FormData, File, Blob
      // - Node 专属: Stream
      data: {
        firstName: 'Fred'
      },
    
      // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
      // 如果请求话费了超过 `timeout` 的时间,请求将被中断
      timeout: 1000,
    
       // `withCredentials` 表示跨域请求时是否需要使用凭证
      withCredentials: false, // default
    
      // `adapter` 允许自定义处理请求,以使测试更轻松
      // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
      adapter: function (config) {
        /* ... */
      },
    
     // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
      // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
      auth: {
        username: 'janedoe',
        password: 's00pers3cret'
      },
    
       // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
      responseType: 'json', // default
    
      // `responseEncoding` indicates encoding to use for decoding responses
      // Note: Ignored for `responseType` of 'stream' or client-side requests
      responseEncoding: 'utf8', // default
    
       // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
      xsrfCookieName: 'XSRF-TOKEN', // default
    
      // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
      xsrfHeaderName: 'X-XSRF-TOKEN', // default
    
       // `onUploadProgress` 允许为上传处理进度事件
      onUploadProgress: function (progressEvent) {
        // Do whatever you want with the native progress event
      },
    
      // `onDownloadProgress` 允许为下载处理进度事件
      onDownloadProgress: function (progressEvent) {
        // 对原生进度事件的处理
      },
    
       // `maxContentLength` 定义允许的响应内容的最大尺寸
      maxContentLength: 2000,
    
      // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
      validateStatus: function (status) {
        return status >= 200 && status < 300; // default
      },
    
      // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
      // 如果设置为0,将不会 follow 任何重定向
      maxRedirects: 5, // default
    
      // `socketPath` defines a UNIX Socket to be used in node.js.
      // e.g. '/var/run/docker.sock' to send requests to the docker daemon.
      // Only either `socketPath` or `proxy` can be specified.
      // If both are specified, `socketPath` is used.
      socketPath: null, // default
    
      // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
      // `keepAlive` 默认没有启用
      httpAgent: new http.Agent({ keepAlive: true }),
      httpsAgent: new https.Agent({ keepAlive: true }),
    
      // 'proxy' 定义代理服务器的主机名称和端口
      // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
      // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
      proxy: {
        host: '127.0.0.1',
        port: 9000,
        auth: {
          username: 'mikeymike',
          password: 'rapunz3l'
        }
      },
    
      // `cancelToken` 指定用于取消请求的 cancel token
      // (查看后面的 Cancellation 这节了解更多)
      cancelToken: new CancelToken(function (cancel) {
      })
    }
    

    3.7. 响应结构

    某个请求的响应包含以下信息

    {
      // `data` 由服务器提供的响应
      data: {},
    
      // `status` 来自服务器响应的 HTTP 状态码
      status: 200,
    
      // `statusText` 来自服务器响应的 HTTP 状态信息
      statusText: 'OK',
    
      // `headers` 服务器响应的头
      headers: {},
    
       // `config` 是为请求提供的配置信息
      config: {},
     // 'request'
      // `request` is the request that generated this response
      // It is the last ClientRequest instance in node.js (in redirects)
      // and an XMLHttpRequest instance the browser
      request: {}
    }
    

    使用 then 时,你将接收下面这样的响应 :

    axios.get('/user/12345')
      .then(function(response) {
        console.log(response.data);
        console.log(response.status);
        console.log(response.statusText);
        console.log(response.headers);
        console.log(response.config);
      });
    

    在使用 catch 时,或传递 rejection callback 作为 then 的第二个参数时,响应可以通过 error 对象可被使用,正如在错误处理这一节所讲。

    3.8. 配置默认值

    你可以指定将被用在各个请求的配置默认值

    3.8.1. 全局的 axios 默认值
    axios.defaults.baseURL = 'https://api.example.com';
    axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    
    3.8.2. 自定义实例默认值
    // Set config defaults when creating the instance
    const instance = axios.create({
      baseURL: 'https://api.example.com'
    });
    
    // Alter defaults after instance has been created
    instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
    
    3.8.3. 配置的优先顺序

    配置会以一个优先顺序进行合并。这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者。这里是一个例子:

    // 使用由库提供的配置的默认值来创建实例
    // 此时超时配置的默认值是 `0`
    var instance = axios.create();
    
    // 覆写库的超时默认值
    // 现在,在超时前,所有请求都会等待 2.5 秒
    instance.defaults.timeout = 2500;
    
    // 为已知需要花费很长时间的请求覆写超时设置
    instance.get('/longRequest', {
      timeout: 5000
    });
    

    3.9. axios实例对象

    3.9.1. 创建实例

    可以使用自定义配置新建一个 axios 实例

    axios.create([config])

    const instance = axios.create({
      baseURL: 'https://some-domain.com/api/',
      timeout: 1000,
      headers: {'X-Custom-Header': 'foobar'}
    });
    
    

    3.10. 拦截器

    在请求或响应被 thencatch 处理前拦截它们。

    // 添加请求拦截器
    axios.interceptors.request.use(function (config) {
        // 在发送请求之前做些什么
        console.log("请求拦截器 成功");
        return config;
      }, function (error) {
        // 对请求错误做些什么
        console.log("请求拦截器 失败");
        return Promise.reject(error);
      });
    
    // 添加响应拦截器
    axios.interceptors.response.use(function (response) {
        // 对响应数据做点什么
        console.log("响应拦截器 成功");
        return response;
      }, function (error) {
        // 对响应错误做点什么
        console.log("响应拦截器 失败");
        return Promise.reject(error);
      });
    

    如果你想在稍后移除拦截器,可以这样:

    const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
    axios.interceptors.request.eject(myInterceptor);
    

    可以为自定义 axios 实例添加拦截器

    const instance = axios.create();
    instance.interceptors.request.use(function () {/*...*/});
    

    3.11. 取消请求(cancel token )

    使用 cancel token 取消请求

    Axios 的 cancel token API 基于cancelable promises proposal,它还处于第一阶段。

    可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:

    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    
    axios.get('/user/12345', {
      cancelToken: source.token
    }).catch(function(thrown) {
      if (axios.isCancel(thrown)) {
        console.log('Request canceled', thrown.message);
      } else {
         // 处理错误
      }
    });
    
    axios.post('/user/12345', {
      name: 'new name'
    }, {
      cancelToken: source.token
    })
    
    // 取消请求(message 参数是可选的)
    source.cancel('Operation canceled by the user.');
    

    还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:

    const CancelToken = axios.CancelToken;
    let cancel;
    
    axios.get('/user/12345', {
      cancelToken: new CancelToken(function executor(c) {
        // executor 函数接收一个 cancel 函数作为参数
        cancel = c;
      })
      // cancelToken: new axios.CancelToken(function (c) {
      //  cancel = c;
      })
    });
    
    // cancel the request
    cancel();
    

    注意: 可以使用同一个 cancel token 取消多个请求

    3.12. 源码阅读

    4. fetch函数

    fetch("http://example.com/movies.json", {
    	// 请求方法
    	method: "POST",
    	headers: {
    		name: "zs",
    	},
    	body: "username=admin&password=admin",
    })
    	.then(function (response) {
    		return response.json();
    	})
    	.then(function (myJson) {
    		console.log(myJson);
    	});
    
    

    5. 跨域

    5.1. 同源策略

    同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。

    同源: 协议、域名、端口号 必须完全相同, 违背同源策略就是跨域。

    5.2. JSONP

    JSONP ( JSON with Padding ),是一个非官方的跨域解决方案,只支持 get 请求。

    JSONP 利用 script 标签的跨域能力来发送请求的。

    JSONP :

    // 1. 动态的创建一个 script 标签 
    let script = document.createElement("script"); 
    
    // 2. 设置 script 的 src,设置回调函数 
    script.src = "http://localhost:3000/testAJAX?callback=abc"; 
    function abc(data) {
        alert(data.name); 
    }; 
    
    // 3. 将 script 添加到 body 中 
    document.body.appendChild(script); 
    
    // 4. 服务器中路由的处理 
    router.get("/testAJAX" , function (req , res) { 
        console.log("收到请求"); 
        let callback = req.query.callback; 
        let obj = { name:"孙悟空", age:18 } 
        res.send(callback+"("+JSON.stringify(obj)+")"); 
        // res.end(`callback(${JSON.stringify(obj)})`)
    });
    

    5.3. JQuery -jsonp

      <script src="http://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
      
    <!-- 动态创建script标签 -->
      <script>
        function hello(data) {
          console.log(data)
        }
        let script = document.createElement('script');
        script.src = 'https://www.baidu.com/jquery-server?callback=?'
        let body = document.getElementsByTagName('body')[0]
        body.appendChild(script)
      </script>
      
      <script type="text/javascript">
        $.getJSON("http://127.0.0.1:3300/jquery-server?callback=?", function(data) {
    		console.log(data)
        });
      </script>
    

    5.4. 模仿jQuery封装jsonp

    function ajax(obj){
        // jsonp仅仅支持get请求
        var defaults = {
            url : '#',
            dataType : 'jsonp',
            jsonp : 'callback',
            data : {},
            success:function(data){console.log(data);}
        }
        for(var key in obj){
            defaults[key] = obj[key];
        }
        // 这里是默认的回调函数名称
        // expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
        var cbName = 'jQuery' + ('1.11.1' + Math.random()).replace(/\D/g,"") + '_' + (new Date().getTime());
        if(defaults.jsonpCallback){
            cbName = defaults.jsonpCallback;
        }
        // 这里就是回调函数,调用方式:服务器响应内容来调用
        // 向window对象中添加了一个方法,方法名称是变量cbName的值
        window[cbName] = function(data){
            defaults.success(data);//这里success的data是实参
        }
        var param = '';
        for(var attr in defaults.data){
            param += attr + '=' + defaults.data[attr] + '&';
        }
        if(param){
            param = param.substring(0,param.length-1);
            param = '&' + param;
        }
        var script = document.createElement('script');
        script.src = defaults.url + '?' + defaults.jsonp + '=' + cbName + param;
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(script);
        // abc({"username":"zhangsan","password":"123"})
    }
    

    6. CORS

    MDN

    ​ CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方 案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。

    ​ CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应 以后就会对响应放行。

    // 引入express模块
    const express = require('express')
    const app = express()
    const port = 3000
    app.get('/', (req, res) => {
        // JSON格式 JSON.stringify(data)
      res.send('Hello World!')
    })
    // 如果参数值中有中文,比如张三丰,则用encodeURI对中文进行编码 data = "username="+encodeURI("张三丰")+"&password=2016";
    
    
    // 设置响应头,允许跨域
    	response.setHeader('Access-Control-Allow-Origin','*');
    // 允许任何类型的请求头
    	response.setHeader('Access-Control-Allow-Headers','*')
    // 设置请求方法
    	response.setHeader('Access-Control-Allow-Method','*')
    
    // 监听端口启动服务
    app.listen(port, () => {
      console.log(`Example app listening at http://localhost:${port}`)
    })
    

    7. Promise

    ​ 语法上Promise是一个构造函数,内部封装异步操作并可以获取其成功或失败的结果,异步编程的一种解决方案,用来解决回调地狱(在回调函数外面处理接收的数据)。

    Promise三种状态:

    1. pending[等待]等待状态
    2. fulfilled[满足]满足状态
    3. rejected[拒绝]拒绝状态

    当promise状态发生改变,就会触发then()里的响应函数处理后续步骤。

    Promise状态改变只有:

    1. 从pending变为fulfilled
    2. 从pending变为rejected

    promise状态一经改变,不会再变。

    const p = new Promise((resolve, reject) => {
    	setTimeout(function () {
    		resolve("数据!"); // pending --> fulfilled
    		reject("error!"); // pending --> rejected
    	}, 1000);
    });
    
    // then方法和catch方法返回的结果都是promise对象,对象状态由回调函数的执行结果决定(PromiseStatus,PromiseValue)
    // 链式调用
    
    p.then(res => {
        console.log(res);
    }).catch(err => {
        console.log(err);
    })
    
    p.then(
    	res => {
    		console.log(res);
    	},
    	err => {
    		console.log(err);
    	}
    );
    

    Promise对象的值:

    实例对象中的另一个属性【PromiseResult】

    保存着对象 【成功/失败】的结果

    • resolve

    • reject

    Promise方法:

    • resolve

    • reject

    • all 参数中Promise全部返回成功才成功,返回一个新的Promise

    • race 参数中第一个完成Promise的结果状态就是最终的状态,返回一个新的Promise

    Promise异常穿透:

    1. 使用Promise的then链式调用时,可以在最后指定失败的回调。
    2. 前面任何操作出了异常,都会传到最后失败的回调中处理
    3. 想要中断Promise的then链式调用,返回一个pending状态的promise函数

    7.1 util.promisify

    const fs = require('fs');
    
    // const util = require('util');
    // const readFileAsync = util.promisify(fs.readFile);
    const { promisify } = require('util');
    
    const readFileAsync = promisify(fs.readFile);
    
    async function read() {
        const content = await readFileAsync('./test.js', 'utf-8');
        return content;
    }
    
    read().then(v => {
        console.log(v);
    });
    

    7.2 promise自定义封装

    class Promise{
        //构造方法
        constructor(executor){
            //添加属性
            this.PromiseState = 'pending';
            this.PromiseResult = null;
            //声明属性
            this.callbacks = [];
            //保存实例对象的 this 的值
            const self = this;// self _this that
            //resolve 函数
            function resolve(data){
                //判断状态
                if(self.PromiseState !== 'pending') return;
                //1. 修改对象的状态 (promiseState)
                self.PromiseState = 'fulfilled';// resolved
                //2. 设置对象结果值 (promiseResult)
                self.PromiseResult = data;
                //调用成功的回调函数
                setTimeout(() => {
                    self.callbacks.forEach(item => {
                        item.onResolved(data);
                    });
                });
            }
            //reject 函数
            function reject(data){
                //判断状态
                if(self.PromiseState !== 'pending') return;
                //1. 修改对象的状态 (promiseState)
                self.PromiseState = 'rejected';// 
                //2. 设置对象结果值 (promiseResult)
                self.PromiseResult = data;
                //执行失败的回调
                setTimeout(() => {
                    self.callbacks.forEach(item => {
                        item.onRejected(data);
                    });
                });
            }
            try{
                //同步调用『执行器函数』
                executor(resolve, reject);
            }catch(e){
                //修改 promise 对象状态为『失败』
                reject(e);
            }
        }
    
        //then 方法封装
        then(onResolved,onRejected){
            const self = this;
            //判断回调函数参数
            if(typeof onRejected !== 'function'){
                onRejected = reason => {
                    throw reason;
                }
            }
            if(typeof onResolved !== 'function'){
                onResolved = value => value;
                //value => { return value};
            }
            return new Promise((resolve, reject) => {
                //封装函数
                function callback(type){
                    try{
                        //获取回调函数的执行结果
                        let result = type(self.PromiseResult);
                        //判断
                        if(result instanceof Promise){
                            //如果是 Promise 类型的对象
                            result.then(v => {
                                resolve(v);
                            }, r=>{
                                reject(r);
                            })
                        }else{
                            //结果的对象状态为『成功』
                            resolve(result);
                        }
                    }catch(e){
                        reject(e);
                    }
                }
                //调用回调函数  PromiseState
                if(this.PromiseState === 'fulfilled'){
                    setTimeout(() => {
                        callback(onResolved);
                    });
                }
                if(this.PromiseState === 'rejected'){
                    setTimeout(() => {
                        callback(onRejected);
                    });
                }
                //判断 pending 状态
                if(this.PromiseState === 'pending'){
                    //保存回调函数
                    this.callbacks.push({
                        onResolved: function(){
                            callback(onResolved);
                        },
                        onRejected: function(){
                            callback(onRejected);
                        }
                    });
                }
            })
        }
    
        //catch 方法
        catch(onRejected){
            return this.then(undefined, onRejected);
        }
    
        //添加 resolve 方法
        static resolve(value){
            //返回promise对象
            return new Promise((resolve, reject) => {
                if(value instanceof Promise){
                    value.then(v=>{
                        resolve(v);
                    }, r=>{
                        reject(r);
                    })
                }else{
                    //状态设置为成功
                    resolve(value);
                }
            });
        }
    
        //添加 reject 方法
        static reject(reason){
            return new Promise((resolve, reject)=>{
                reject(reason);
            });
        }
    
        //添加 all 方法
        static all(promises){
            //返回结果为promise对象
            return new Promise((resolve, reject) => {
                //声明变量
                let count = 0;
                let arr = [];
                //遍历
                for(let i=0;i<promises.length;i++){
                    //
                    promises[i].then(v => {
                        //得知对象的状态是成功
                        //每个promise对象 都成功
                        count++;
                        //将当前promise对象成功的结果 存入到数组中
                        arr[i] = v;
                        //判断
                        if(count === promises.length){
                            //修改状态
                            resolve(arr);
                        }
                    }, r => {
                        reject(r);
                    });
                }
            });
        }
    
        //添加 race 方法
        static race (promises){
            return new Promise((resolve, reject) => {
                for(let i=0;i<promises.length;i++){
                    promises[i].then(v => {
                        //修改返回对象的状态为 『成功』
                        resolve(v);
                    },r=>{
                        //修改返回对象的状态为 『失败』
                        reject(r);
                    })
                }
            });
        }
    }   
    
    
    

    8. async 函数和 await 表达式

    8.1 async 函数

    1. 函数的返回值为 promise 对象
    2. promise 对象的结果由 async 函数执行的返回值决定

    8.2 await 表达式

    1. await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
    2. 如果表达式是 promise 对象, await 返回的是 promise 成功的值
    3. 如果表达式是其它值, 直接将此值作为 await 的返回值
    4. await 必须写在 async 函数中, 但 async 函数中可以没有 await
    5. 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
    /**
     * resource  1.html  2.html 3.html 文件内容
     */
    
    const fs = require('fs');
    const util = require('util');
    const mineReadFile = util.promisify(fs.readFile);
    
    //回调函数的方式
    // fs.readFile('./resource/1.html', (err, data1) => {
    //     if(err) throw err;
    //     fs.readFile('./resource/2.html', (err, data2) => {
    //         if(err) throw err;
    //         fs.readFile('./resource/3.html', (err, data3) => {
    //             if(err) throw err;
    //             console.log(data1 + data2 + data3);
    //         });
    //     });
    // });
    
    //async 与 await
    async function main(){
        try{
            //读取第一个文件的内容
            let data1 = await mineReadFile('./resource/1x.html');
            let data2 = await mineReadFile('./resource/2.html');
            let data3 = await mineReadFile('./resource/3.html');
            console.log(data1 + data2 + data3);
        }catch(e){
            console.log(e.code);
        }
    }
    
    main();
    
    展开全文
  • 除了vue-resource之外,还可以使用’axios‘的第三方包实现数据的请求因为跨域失败访问不到,不过同域的可以直接访问.html文件来检验,这样可以不用搭服务器建议使用axios来进行异步访问请求 1.安装或导入vue-...
  • 异步请求的执行原理来看,我们知道当一个异步请求发送时,浏览器不会处于锁死、等待的状态,从一个异步请求发送到获取响应结果的期间,浏览器还可以进行其它的操作。这就意味着多个异步请求的执行时并...
  • 由于小程序网络请求大小限制,我们只能采取循环上传单文件,然后收集每次请求的结果–图片在服务器的地址,最后将结果放在一个数组中供后续的操作使用。 当图片上传函数全部执行完毕后,将数组中的图片数组取出来...
  • 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 ...简单来说就是异步处理,异步加载数据等 二、异步和同步又是什么? 简单来说: 同步就是我强依赖你(对方),我必须等到你的回复,才能做出下一.
  • okhttp3同步请求和异步请求小案例

    千次阅读 2022-03-16 15:30:09
    学习内容:okhttp3同步请求和异步请求 OkHttp开源库进行访问 步骤: 1.app/build.gradle文件在dependencies闭包中添加如下内容: implementation ‘com.squareup.okhttp3:okhttp:4.4.0’ 2.创建OkHttpClient类的...
  • Vue中进行异步请求

    万次阅读 2018-09-06 17:49:50
    前端的数据均是通过接口请求拿到的,而Vue本身不支持ajax请求,那么该怎么解决Vue中的异步请求呢?这儿提供了几种方法,希望对大家有所帮组。 一、axios实现异步请求 1.项目中安装axiox npm install –...
  • Android 中Okhttp的同步请求与异步请求详解

    千次阅读 热门讨论 2021-05-28 22:01:17
    同步请求与异步请求的概念: 简单地说,同步就是发出一个请求后什么事都不做,一直等待请求返回后才会继续做事;异步就是发出请求后继续去做其他事,这个请求处理完成后会通知你,这时候就可以处理这个回应了。 写了...
  • 一般只使用第一个参数,第一个参数表示响应的数据 error(xhr,status,error):如果请求失败要运行的函数。 complete(xhr,status):请求完成时运行的函数(在请求成功或失败之后均调用,即在 success 和 error 函数...
  • ajax同步请求和异步请求

    千次阅读 2019-10-15 20:36:49
    ajax同步请求和异步请求前序什么是同步请求?什么是异步请求?比较同步和异步请求 前序 最近好长时间没写博客了,主要由于前一段时间出差,没啥心思写,今天开始重新继续。进入主题,ajax的同步请求和异步请求,这个...
  • ajax 请求失败的原因

    万次阅读 2017-10-20 15:25:52
     failure: function() { alert("获取目录请求失败!"); } // 请求失败的回调函数   });      注意:做了以上操作后在IE、google chrome、firefox11下是没有问题的,但到了firefox12下去看,就发现...
  • 基于django的异步请求总结

    千次阅读 2019-01-12 11:03:08
    }//请求失败后执行的函数 } )//创建ajax对象 } ) } ) 案例 这里有一个简单的注册案例:用户只需要输入用户名和密码便可以完成注册,我们需要在用户输入用户名后验证改用户名是否已经存在,如果用户名...
  • 一、AJAX - 阿贾克斯 1、什么是AJAX? Asynchronous Javascript And Xml 是可以创建快速动态网页的技术。... 同步访问:当客户端向服务器发送请求时,服务器在处理过程中,浏览器只能等待,效率偏 ...
  • vue多个异步请求解决

    2022-01-13 14:29:11
    vue单页面多个请求时优化
  • 我们在编写前端程序的时候,往往需要异步请求后端数据,然后拿着得到的数据重现渲染页面。有的时候,数据还没有获取到,这个时候会是undefined形式。比如说,let test = "123",但是后端还没有传回来数据的话,会是...
  • await异步请求处理办法 目录async&await异步请求处理办法前言一、async1、async函数2、回调async函数以获取结果二、await末 前言 async函数(官方):使用async关键字声明的函数,是AsyncFunction构造函数的实例, ...
  • java —— 异步任务失败后处理

    千次阅读 2019-06-29 23:24:04
    场景: ...但是如果是异步操作,比如用户注册成功后,系统异步发送短信给用户,发短信的操作出问题了没有发出去,而且这个操作也不是用户主动操作了,所以可能会出现用户不知道你有这个操作,系统...
  • 异步请求promise

    千次阅读 2019-03-05 22:29:58
    传统的异步请求 var xhr = new XMLHttpRequest(); //创建xhr实例对象 xhr.open("get", "http://www.blogzl.com/zl_other_module/ajaxTest/getTest.php?doWhat=张三"); //创建ajax请求 xhr....
  • IOS开发中异步网络请求上实现同步逻辑 前提: 可能遇到一些问题,比如上传多个数据,需要等多个数据上传成功后做一定的处理,而且一个个上传,万一哪个上传失败了,后面就不需要上传了,直接报错。 之前ASI的网络库...
  • rejected:失败操作 promise的一个便利是,针对多个异步请求的情况,可以使用 Promise.all 方法来确保各个请求的执行返回,避免了“回调地狱”。 pending 状态可以转换为 fulfilled 或者 rejected ,并且只能转换一...
  • 多个异步请求顺序进行 即在请求完接口1的数据data1之后,需要根据data1的数据,继续请求接口2,获取data2,然后根据data2的数据,继续请求接口3…… function myFun01() { console.log('以下内容是在myFun01中输出...
  • C# 异步请求HTTP接口

    千次阅读 2020-04-10 15:53:08
    说明: 因为经常需要调用Htpp接口,所以封装了一个类,一是为了方便调用Http...仅有Get、Post两种异步请求接口的方式。 Get、Post方法封装 private HttpClient httpClient; public HttpUtil() { HttpCli...
  • 前端可用的异步请求方案

    千次阅读 2022-04-25 09:30:51
    前端可用的异步请求方案
  • jQuery Ajax异步请求详解

    千次阅读 2019-02-23 15:14:32
    jQuery的Ajax API是对XMLHttpRequest对象的抽象,...关于XMLHttpRequest对象请参照我的另一篇博客:XMLHttpRequest进行异步请求(包括文件上传)详解 核心概念 GET or POST GET用于从服务器获取数据 POST用于向服...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 217,322
精华内容 86,928
关键字:

异步请求失败