如果遇到过深度回调的朋友一定对JS的回调地狱再熟悉不过了,举个例子说(如果我的列子不恰当尽请谅解),常见的就是省市区级联吧,假如我要获取一个县级市的信息,那么我首先得获得它所在的省的信息,当取得省的信息以后,再拉去地级市的信息,当获得地级市的信息以后,然后才有可能获取到它的信息。这就是典型的深度回调的业务场景。这使得开发人员变得痛苦不堪,代码的质量难以得到保证。
对此,ES6中引入了一个Promise对象来解决此类问题(本文只做大概的讲解),Promise,中文是诺言的意思,表示一段时间(pending)之后一定会获得的结果(resolved状态或者说是fullfilled状态),当然有可能获得的结果是错误的(rejected)。语法是:
function asyncReadFile() {
return new Promise((resolve, reject) => {
var counter = 0;
var timer = setInterval(() => {
counter++;
console.log({
counter
})
if (counter >= 3) {
clearInterval(timer);
resolve('hello world');
}
}, 1000)
})
}
然后我们通过asyncReadFile().then(result => { console.log(result) }) 打印出hello world!。
对于之前的省市县级联的业务,我们可以利用Promise改写成:
getProvinces().then(result => {
console.log('省级行政区域的信息为:' + result)
return getCities()
}).then(result => {
console.log('地级行政区域的信息为:' + result)
return getAreas()
}).then(result => {
console.log('县级行政区域的信息为:' + result)
})
假设getProvince、getCities、getAreas都返回一个Promise对象,本来深度回调的代码,就变成了串行的代码。(请大家避免如下书写有关Promise的代码)
getProvinces().then(result => {
console.log('省级行政区域的信息为:' + result)
getCities().then(result => {
console.log('地级行政区域的信息为:' + result)
getAreas().then(result => {
console.log('县级行政区域的信息为:' + result)
})
})
})
虽然Promise解决了深度回调的问题,但是却引入了大量无用的代码,你会写很多then,代码也变得很难看了。
于是,ES7中加入了async和await这对关键字。
await 命令只能用在async函数之中。async函数是基于Generator函数的实现,由于我们直接跳过了generator,这儿必须得提一个概念叫做协程,才便于大家对async函数的理解。就是函数在执行的时候,如果遇到一些条件,它会将执行条件交给另外的函数,等另外的函数执行完成之后,再将执行权力交回继续执行。(纯属个人理解,如果纰漏,尽情指出)。
画个图就是如下:
async function asyncGetFileInfo() { var fileInfo await getFileInfo(); return fileInfo; }
这段代码的意思正如上图所示。async函数返回的是一个Promise,我们这样来理解吧,里面既然是异步的东西,肯定有些东西要等一会儿才可以得到吧。而await(await紧跟一个Promise)直接是取得异步的结果,我们可以不用再调用then。
然后 刚才那么多Promise组成的获得行政区域的信息的方法可以简化成如下代码:
async function getDistrictInfo() {
var province = await getProvinces();
var city = await getCities();
var area = await getAreas();
return `${province}省(市,自治区)${city}市(区)${area}县市区旗`
}
getDistrictInfo().then(result => { console.log(result); });
由于ES7太新,浏览器支持的不太好(nodejs请放心使用),我们需要babel进行转码。
npm install --save-dev babel-preset-latest