ES6/7/8新特性Promise,async,await,fetch带我们逃离异步回调的深渊

Promise:
在ES6以前如果我们需要在js中进行异步处理,大多数都是通过使用回调函数的方式来解决问题,如果简单的异步处理,回调函数的方式看起来还是比较优雅的,逼格还有点高,但是如果异步操作很多,回调嵌套就很深,代码看起来就会特别别扭,维护起来成本也会变高这个时候ES6带来Promise这个新特性,这个方法很好的解决了深层次异步嵌套的问题,我们在写代码的时候可以采用类似linux流式的书写方式:
例如:

 flow().then(function(success){}).catch(function(error){})

这样的异步操作看起来就非常直观了。下面是一个完整Proimise例子

function flow(flag){
       //promise是一个构造函数,内部接收一个回调函数。
       //回调函数内部有两个参数,reslove是执行成功的时候调用的,reject是失败调用的
       var promise = new Promise(function(reslove,reject){
          setTimeout(function(){//模拟异步操作
               if(flag){
                 reslove(true);//处理成功
               }else{
                 reject(false)处理失败
               }
          },5000)
       });
       return promise;
   }
   //flow返回的是一个Promise对象,这样我们就能通过下面的方式来的处理异步操作了。
   //调用该函数
   flow().then(function(success){     
   }).catch(function(error){
        //处理失败返回
   });

reslove代表处理成功,对应后面的then,reject代表处理失败,对应后面的catch,resolve和reject里面值可以是字符串,也可以是对象,这个值可以理解成Promise的返回值。
Promise不经有then,catch,还有all,race,具体怎么用找度娘。其实就是同时获取多个Promise对象返回值得操作。

看见上面的Promise的用法,熟悉jquery的司机是不是有点似曾相识的赶脚。其实在jquery1.5版本以后,$.ajax就可以使用上面那种流式的操作了,开始逐渐摈弃回调的方式。

$.ajax({}).then(function(result){}).fail(function(error){})

如果你还在使用success,error的回调函数的这种方式,呵呵。。。。
jquey使用了Deferred的方式实现的类似Promise的功能,在jquery1.7以后, .Deferred .Deferred和Promise的使用方式几乎就是一个模子里面刻出来的:

function runAsync(){
    var def = $.Deferred();
    //做一些异步操作
    setTimeout(function(){//模拟异步操作
        def.resolve('随便什么数据');
    }, 2000);
    return def;
}
runAsync().then(function(data){
    console.log(data)
});

讲完了Proimise,现在来讲讲async和await
async,await语法糖
async和await是ES7新增的规范,两个规范可以看成一队连体婴,他们要一起出现才有效果:

var stop= function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve();
        }, time);
    })
};

var start = async function () {
    // 在这里使用起来就像同步代码那样直观
    console.log('start');
    var result = await stop(3000);
    console.log('end');
};
start();

要注意await只能在async中使用,不然是没有效果的。其实async 和await联合起来使用相当于替代了Promise的then和catch方法,将async低昂一的函数里面的代码由异步变成了同步阻塞式,只有当await定义的行数执行完了代码才会继续往下执行,同时await还有有返回值,他的返回值在上面这个例子中就是resolve,reject的值需要通过try {}catch(err){},捕获:

var start = async function () {
    // 在这里使用起来就像同步代码那样直观
    console.log('start');
    try{
      await stop(3000);
    }catch(err){
      console.log(err);
    }
    console.log('end');
};
start();

await后面的应该跟一个Promise的对象或者fetch(后面讲),不然结果会有点怪怪的,我直接在后面加一个setTimeout,结果然我很是不解,有兴趣的可以分别执行下面两段代码,结果超乎你的想象:

var start1 = async function () {
    // 在这里使用起来就像同步代码那样直观
    console.log('start');
   var a = await setTimeout(function(){console.log("---")},5000)
    console.log('end'+a);
};  start1();console.log("----");
var start2 = async function () {
    // 在这里使用起来就像同步代码那样直观
    console.log('start');
   var a = await setTimeout(function(){console.log("---")},5000)
    console.log('end'+a);
};  start();console.log("----");for(var i=0; i<10;i++){console.log(i)}

其实个人感觉还是喜欢直接使用Promise实现异步操作,感觉async和await有点把事情搞复杂了。当然居然人家把他作为了ES7的规范,而且是为数不多的规范,那么他就有用武之地。特别是如果我们有时候js代码需要同步操作的时候。

fetch:
这个方法是ES2017中新增的特性,这个特性出来后给人一种传统ajax已死的感觉,其实它的作用是替代浏览器原生的XMLHttpRequest异步请求,我们在日常的开发中,基本不会自己去写XMLHttpRequest,主要是太复杂了,都是使用已经封装好了的各种插,件常用的有jquery,npm包管理工具也提供了axios,request等模块。而有了fetch后我们就可以在不用这些插件的情况下快速简单的实现异步请求了:
get请求:

 var word = '123',
 url = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+word+'&json=1&p=3';
fetch(url,{mode: "no-cors"}).then(function(response) {
 return response;
}).then(function(data) {
 console.log(data);
}).catch(function(e) {
 console.log("Oops, error");
});

post请求:

var headers = new Headers();
headers.append("Content-Type", "application/json;");
fetch(url, {
 method: 'post',
 headers: headers,
 body: JSON.stringify({
 date: '2016-10-08',
 time: '15:16:00'
 })
});

上面这种写法其实和我们常用的ajax插件写法就比较像了,但是要注意目前原生的fetch还不支持jsonp的请求方式,如果需要实现jsonp,需要安装npm包fetchJ-jsonp,使用方式:

fetchJsonp(url, {
 timeout: 3000,
 jsonpCallback: 'callback'
}).then(function(response) {
 console.log(response.json());
}).catch(function(e) {
 console.log(e)
});

我们可以通过new Header构建我们的请求头:

var headers = new Headers();
headers.append("Content-Type", "text/html");
fetch(url,{
 headers: headers
});

请求头也是可以被索引:

var header = new Headers({
 "Content-Type": "text/plain"
});
console.log(header.has("Content-Type")); //true
console.log(header.has("Content-Length")); //false

fetch可以设置不同的模式使得请求有效. 模式可在fetch方法的第二个参数对象中定义.
通过上面fetch的使用方式,可以看出他和Promise的使用方式非常相像,fetch其实返回的就是一个Promise对象,async,await也就和fetch是完美兼容了,我们可以使用async,await实现代码的同步:

(async ()=>{
 try {
 let res = await fetch(url, {mode: 'no-cors'});//等待fetch被resolve()后才能继续执行
 console.log(res);
 } catch(e) {
   console.log(e);
 }
})();

这篇文章主要梳理了一下Promise,async,await,fetch之间的关系,Primise是基础,async,await,fetch是踩在Promise的肩膀上。

猜你喜欢

转载自blog.csdn.net/wang839305939/article/details/75505444
今日推荐