JavaScript(04-1)AJAX & PROMISE

AJAX

一、基本使用

1、概念

  • Ajax 即 Asynchronous Javascript And XML(异步 JavaScript 和 XML);
  • 一般的情况是一次http请求对应一个页面,ajax 要实现的就是在页面不跳转的情况下发送请求、获取数据、实现网页局部刷新

1.eval(str)可以将 str 解析为 js 执行;
2.浏览器缓存是根据 url 进行缓存的,变更 url 可以阻止浏览器的缓存;
3.js 的变量与属性:使用未定义的变量会报错;使用未定义的属性仅仅是 undefine,不会报错;

2、原理

XHR对象
  • 一般情况下请求的发送和响应的接受都是由浏览器完成,AJAX将这个过程交给了XHR对象
  • XHR对象重要的属性:readyState、onreadystatechange、status、statusText
简单封装
  • 发送请求:注意 get 和 post 请求发送的差异
  • 接受响应:responseText、responseXML(xml的解析和html的解析类似,XHR对象内置了解析器)
  • AJAX请求的几种状态说明:
0:未初始化,还未调用 open 方法;
1:载入,已调用 send 方法,正在发送去请求;
2:载入完成,send 方法完成,收到所有的响应内容;
3:解析,解析响应内容;
4:完成,解析完成,可以在客户端使用了;
function myAjax(method,url,data,async,sucFn,faiFn){
    //get ajax obj
    if(window.XMLHttpRequest)
    {
        var oAjax=new XMLHttpRequest();
    }
    else
    {
        var oAjax=new ActiveXObject("Microsoft.XMLHTTP");
    }
    //state listener
    oAjax.onreadystatechange=function ()
    {
        if(oAjax.readyState==4)    
        {
            if(oAjax.status==200)
            {
                if(sucFn){
                    sucFn(oAjax);
                }
            }
            else
            {
                if(faiFn){
                    faiFn(oAjax);
                }
            }
        }
    };
    //connection check method
    if(method.toUpperCase() == "GET"){
        oAjax.open(method, url+(data ? '?'+data : ''), async);
        oAjax.send(data);
    }else if(method.toUpperCase() == "POST"){
        oAjax.open(method, url, async);
        oAjax.setRequestHeader("Content-type","application/x-www-form-urlencoded");  
        oAjax.send(data);
    }   
}

二、安全限制

  • 出于安全原因 ajax 不允许 跨域访问,这意味着ajax请求的资源需和当前的页面在一个服务器上
  • 严格限制的话需要域名相同、协议相同、端口相同

1、JSONP跨域请求

  • 最常用的就是使用 JSONP,实现的原理就是利用了浏览器允许跨域引用JavaScript资源的特性
  • JSONP 有个限制,只能用GET请求,并且要求返回JavaScript
  • JSONP 本质就是添加一个 script 节点进行跨域请求,通过 js 回调函数的参数获取请求的数据
  • 示例代码中需要注意 url 中的 callback 参数,回调函数中的 data 就是我们通过JSONP请求到的数据
  • 请求相应的API返回的数据原本的样子是这样的_ntes_quote_callback({.........}),,实际上是一个js函数,这也是jsonp的限制,通过与我们定义的回调函数的自动匹配将真正需要的数据传入了回调函数的参数里面
<div id="test-jsonp"></div>

<script>
    function refreshPrice(data) {
        var p = document.getElementById('test-jsonp');
        p.innerHTML = '当前价格:' +
            data['0000001'].name + ': ' +
            data['0000001'].price + ';' +
            data['1399001'].name + ': ' +
            data['1399001'].price;
    }

    (function getPrice() {
        var
            js = document.createElement('script'),
            head = document.getElementsByTagName('head')[0];
        js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
        head.appendChild(js);
    })();
</script>

2、CORS跨域请求

  • 这种跨域请求的方式是 H5 的新特性,中文翻译过来就是跨域资源共享
  • 通常JS和CSS资源的请求是无需验证CORS的,但是除了这两个一般都是要验证的
简单请求
  • 请求头中的Origin表示本域,也就是当前页面的域;当JavaScript向外域发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,包含的话就请求成功,否则失败
  • 跨域能否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin
  • 这种请求包括GET、HEAD和POST(POST的Content-Type类型仅限application/x-www-form-urlencoded、multipart/form-data、text/plain),并且不能出现任何自定义头,能满足大部分的需求
    在这里插入图片描述
Options请求
  • 对于PUT、DELETE以及其他类型如application/json的POST请求,在发送AJAX请求之前浏览器会先发送一个OPTIONS请求到这个URL上,与目标服务器进行确认
OPTIONS /path/to/resource HTTP/1.1
Host: bar.com
Origin: http://my.com
Access-Control-Request-Method: POST
  • 服务器的响应需要指明允许的 method,服务器允许的情况才会继续发送ajax请求,否则抛出错误
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://my.com
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 86400

PROMISE

一、promise简介

1、promise 是什么

  • Promise是异步编程的一种解决方案,可以替代传统的解决方案–回调函数和事件
  • ES6统一了用法,并原生提供了Promise对象
  • Promise对象的特点:对象的状态不受外界影响,任何时候Promise都只有一种状态

2、promise 的状态

  • Promise有三种状态:Pending (进行中), Resolved (已完成), Rejected (已失败)
  • Promise从Pending状态开始,如果成功就转到成功态,并执行 resolve 回调函数;如果失败就转到失败状态并执行 reject 回调函数

二、基本用法

1、then

  • 创建 promise 对象会立刻执行里面的函数,这里为了控制函数的执行时机,将promise用了一个函数进行返回
  • then 方法里面的函数,promise的状态转变为成功后会立即执行,promise里面包装的函数通过 resolve 将参数 greet 传到 then 方法里面的函数中
function greet() {
    var promise = new Promise(function (resolve, reject) {
        var greet = "hello  world";
        resolve(greet);
    });
    return promise;
}

greet().then(v => {
    console.log(v);
})

2、reject

  • then 方法里面第一个参数对应 resolve,第二个参数对应 reject
function judgeNumber(num){
    var promise1 = new Promise(function(resolve,reject){
        num =5;
        if(num<5){
            resolve("num小于5,值为:"+num);
        }else{
            reject("num不小于5,值为:"+num);
        }
    });
    return promise1;
}

judgeNumber().then(
    function(message){
        console.log(message);
    },
    function(message){
        console.log(message);
    }
)

3、catch

  • promise 的状态变为失败的时候,reject回调会执行,但是如果没有 reject 有 catch 的话,catch 方法会捕获到失败状态执行里面的函数
  • reject 和 catch 同时存在,promise 失败的话,reject会执行,catch就无法捕获失败状态了
  • 除了 promise 里面主动调用 reject 之外,发生错误和异常的话,then 里面的 reject 回调和 catch 也是能够自动处理的,reject 回调发生异常的话,catch 是能够捕获的,下面的代码有助于理解这一点
function run() {
    return new Promise(function (resolve, reject) {
        console.log(tank);
    })
}

run()
    .then(() => {
    }, function (para) {
        console.log('then_test =>' + para);
        console.log(tesla);
    })
    .catch((haha) => {
        console.log('catch_test =>' + haha)
    });

在这里插入图片描述

三、组合使用

1、链式调用

  • then 和 catch 方法返回的还是一个 promise 对象
function greet(){
    var promise = new Promise(function(resolve,reject){
        var greet = "hello  world";
        resolve(greet);
    });
    return promise;
}
greet().then(v=>{
    console.log(v+1);
    return v;
})
.then(v=>{
    console.log(v+2);
    return v;
})
.then(v=>{
    console.log(v+3);
})

2、多个promise的串行使用

// 0.5秒后返回input*input的计算结果:
function multiply(input) {
    return new Promise(function (resolve, reject) {
        log('calculating ' + input + ' x ' + input + '...');
        setTimeout(resolve, 500, input * input);
    });
}

// 0.5秒后返回input+input的计算结果:
function add(input) {
    return new Promise(function (resolve, reject) {
        log('calculating ' + input + ' + ' + input + '...');
        setTimeout(resolve, 500, input + input);
    });
}

var p = new Promise(function (resolve, reject) {
    log('start new Promise...');
    resolve(123);
});

p.then(multiply)
 .then(add)
 .then(multiply)
 .then(add)
 .then(function (result) {
    log('Got value: ' + result);
});

3、Promise.all使用

  • 同时执行多个异步任务,都完成后执行回调
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

4、Promise.race使用

  • 同时执行多个异步任务,其中一个完成后就执行回调,其他任务的结果丢弃,这种做法往往是为了容错
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

5、AJAX 的 Promise 封装

  • Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了
// ajax函数将返回Promise对象:
function ajax(method, url, data) {
    var request = new XMLHttpRequest();
    return new Promise(function (resolve, reject) {
        request.onreadystatechange = function () {
            if (request.readyState === 4) {
                if (request.status === 200) {
                    resolve(request.responseText);
                } else {
                    reject(request.status);
                }
            }
        };
        request.open(method, url);
        request.send(data);
    });
}

var p = ajax('GET', '/api/categories');
p.then(function (text) { // 如果AJAX成功,获得响应内容
    console.log(text);
}).catch(function (status) { // 如果AJAX失败,获得响应代码
    console.log(status);
});

参考文章:js中的promise详解

发布了153 篇原创文章 · 获赞 51 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/stanwuc/article/details/104068150