您的位置:首页 > Web前端

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

2017-07-20 11:59 771 查看
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的肩膀上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息