引言

promise

目的

为异步操作提供统一接口,解决回调地狱问题,用链式调用的方式执行回调函数

基本事例

//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭完毕!');
            resolve('鸡蛋炒饭');
        }, 1000);
    });
    return p;
}

//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}

function wash(data){
    console.log('开始洗碗:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('洗碗完毕!');
            resolve('干净的碗筷');
        }, 2000);
    });
    return p;
}
// 开始调用
cook()
.then(function(data){
    return eat(data);
})
.then(function(data){
    return wash(data);
})
.then(function(data){
    console.log(data);
});
// 或者如下方法调用
cook()
.then(eat)
.then(wash)
.then(function(data){
    console.log(data);
});
// 输出
开始做饭
做饭完毕
开始吃饭:鸡蛋炒饭
吃饭完毕
开始洗碗:一块碗和一双筷子
洗碗完毕
干净的碗筷

状态转移

  • promise对象返回promise对象
  • promise对象有三种状态:初始-挂起(pending)、成功态(fulfilled)、失败态(rejected);后两者称为就绪(settled);
  • 当reject()或者resolve()异步操作执行后,状态发生改变,初始状态转变为成功或者失败状态,注意reject和resolve是竞争关系;在成功和失败状态里再调用promise对象重置为pending态

基本api

let p = new Promise(function(resolve,reject){
    // 异步请求
    resolve('successCallbackData');
    reject('failCallbackData');
})
// 链式回调写法
p.then(function(data){
    console.log(data)  //  successCallbackData
},function(data){
    console.log(data)  // failCallbackData
});
<!--以上代码只会输出successCallbackData,因为异步请求resolve返回后,promise的状态已经改变,后一句reject不会执行了-->

// then的第二个失败回调也可以用catch链式使用
p.then(data=>{console.log(data)}).catch(data=>{console.log(data)});
// then可以只处理失败回调
p.then(null/undefined,data=>{console.log(data)})

// 简写
Promise.resolve(value);
//等同于以下代码
new Promise(function(resolve){
    resolve(value);
});

promise对象方法

  • resolve 方法把 Promise 的状态置为完成态(Resolved),这时 then 方法就能捕捉到变化,并执行“成功”情况的回调
  • reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”情况的回调(then 方法的第二参数)
  • catch 方法除去失败回调,还可以用来:当then的第一个函数抛出错误,会跳到catch中
  • all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回
  • race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调
p.all([p1,p2]).then(data=>{console.log(data)});
p.race([p1,p2]).then(data=>{console.log(data)});
race使用场景

参数数组中设置一个超时计时器,用来对超时请求进行处理

let p2 = function() {
    let p = new promise((resolve,reject)=>{
        setTimeout(()=>{
            reject('超时了');
        },5000)
    })
}
p.race([p1,p2]).then(data=>{console.log(data)});

Fetch

实例

// jquery ajax
$.ajax({
    url: send_url,
    data: send_data,
    type: 'get',
    dataType: 'json',
    success:function(){},
    error:function(){}
})
// Fetch方式
fetch(url).then(response => response.json())
  .then(data => console.log(data))
  .catch(e => console.log("Oops, error", e))

API详解

fetch(url, options).then(function(response) { 
// handle HTTP response
}, function(error) {
 // handle network error
})

1. options属性

  • method(String): HTTP请求方法,默认为GET
  • body(String): HTTP的请求参数
  • headers(Object): HTTP的请求头,默认为{}
  • credentials(String):默认为omit,忽略的意思,也就是不带cookie;还有两个参数,same-origin,意思就是同源请求带cookie;include,表示无论跨域还是同源请求都会带cookie
  • mode:"cors"参数用来实现cors跨域;"no-cors"不跨域

2. response属性

  • status(number): HTTP返回的状态码,范围在100-599之间
  • statusText(String): 服务器返回的状态文字描述,例如Unauthorized,上图中返回的是Ok
  • ok(Boolean): 如果状态码是以2开头的,则为true
  • headers: HTTP请求返回头
  • body: 返回体,这里有处理返回体的一些方法
  • text(): 将返回体处理成字符串类型
  • json(): 返回结果和 JSON.parse(responseText)一样
  • blob(): 返回一个Blob,Blob对象是一个不可更改的类文件的二进制数据
  • arrayBuffer()
  • formData()

缺点

  • 不支持IE,需要配合Fetch的一些polyfill来支持Fetch-ie8
  • cookie传递
    必须在header参数里面加上credientials:'include',才会如xhr一样将当前cookies带到请求中去
  • fetch和xhr区别
    • fetch虽然底层,但是还是缺少一些常用xhr有的方法,比如能够取消请求(abort)方法
    • fetch 在服务器返回4xx、5xx时是不会抛出错误的,这里需要手动通过,通过response中的ok字段和status字段来判断

Axios

通过npm引入的包,是对ajax的封装,可以使用promise语法

基础实例

<!--get请求-->
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

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

axios API

以axios(config)为例

// 发送 POST 请求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});
<!--相应别名:-->
axios.post(url[, data[, config]])

配置解构

config对象内容

{
    url:'xxx',
    method:'get',
    params:{id:2234},
    data:{},
    ...
}

响应结构

{
  // `data` 由服务器提供的响应
  data: {},

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 服务器响应的头
  headers: {},

  // `config` 是为请求提供的配置信息
  config: {}
}