在 js 异步请求数据时,通常,我们多采用回调函数的方式解决,但是,如果有多个回调函数嵌套时,代码显得很不优雅,维护成本也相应较高。 ES6 提供的 Promise 方法和 ES7 提供的 Async/Await 语法糖可以更好解决多层回调问题。

Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。

await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。

await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。

一个ajax请求时

通常 使用 ajax 请求数据时,会

$.ajax({
url: 'data1.json',
type: 'GET',
success: function (res) {
console.log(res) // 请求成功,则得到结果res
},
error: function(err) {
console.log(err)
}
})

上面可以得到我们想要的结果 res ---> { "url": "data2.json" }

多个ajax请求时

但是 当得到的数据 res 需要用于另一个 ajax 请求时,则需要如下写法:

$.ajax({
url: 'data1.json',
type: 'GET',
success: function (res) {
$.ajax({
url: res.url, // 将 第一个ajax请求成功得到的res 用于第二个ajax请求
type: 'GET',
success: function (res) {
$.ajax({
url: res.url, // 将第二个ajax请求成功得到的res 用于第三个ajax请求
type: 'GET',
success: function (res) {
console.log(res) // {url: "this is data3.json"}
},
error: function(err) {
console.log(err)
}
})
},
error: function(err) {
console.log(err)
}
})
},
error: function(err) {
console.log(err)
}
})

上面出现多个回调函数的嵌套,可读性较差(虽然这种嵌套在平常的开发中少见,但是在node服务端开发时,还是很常见的)

优化方法

使用 promise 链式操作

如下,使用 Promise,进行链式操作,可以使上面的异步代码看起来如同步般易读,从回调地狱中解脱出来。。

function ajaxGet (url) {
return new Promise(function (resolve, reject) {
$.ajax({
url: url,
type: 'GET',
success: function (res) {
resolve(res);
},
error: function(err) {
reject('请求失败');
}
})
})
}; ajaxGet('data1.json').then((d) => {
console.log(d); // {url: "data2.json"}
return ajaxGet(d.url);
}).then((d) => {
console.log(d); // {url: "data3.json"}
return ajaxGet(d.url);
}).then((d) => {
console.log(d); // {url: "this is data3.json"}
})

注意,promise 返回的仍然是 promise

下面两种方式的等效的:

1. 直接使用 promise

    function ajaxPromiseGet(url) {
return new Promise(function (resolve, reject) {
$.ajax({
url: url,
type: 'GET',
success: function (res) {
resolve(res)
},
error: function (err) {
reject('请求失败')
}
})
})
} ajaxPromiseGet(`/products/list/`).then(list => {
if (list) {
console.log(list)
}
})

2. 当需要先统一处理 promise 返回值时

function ajaxPromiseGet(url) {
return new Promise(function (resolve, reject) {
$.ajax({
url: url,
type: 'GET',
success: function (res) {
resolve(res)
},
error: function (err) {
reject('请求失败')
}
})
})
} // 先统一处理 promise
function handleList () {
let ajaxReault = ajaxPromiseGet(`/products/list/`)
return ajaxReault.then(list => {
return list.filter(item => item.status == 0)
})
} handleList().then(list => {
if (list) {
console.log(list)
}
})

Async/await 方法

  • async 表示这是一个async函数,即异步函数,await只能用在这个函数里面。
  • await 表示在这里等待promise返回结果了,再继续执行。
  • await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)
  • await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。
  • await 等待的虽然是promise对象,但不必写.then(..),直接可以得到返回值。

执行一个ajax请求,可以通过如下方法:

function ajaxGet (url) {
return new Promise(function (resolve, reject) {
$.ajax({
url: url,
type: 'GET',
success: function (res) {
resolve(res)
},
error: function(err) {
reject('请求失败')
}
})
})
}; async function getDate() {
console.log('开始')
let result1 = await ajaxGet('data1.json');
console.log('result1 ---> ', result1); // result1 ---> {url: "data2.json"}
}; getDate(); // 需要执行异步函数

执行多个ajax请求时:

function ajaxGet (url) {
return new Promise(function (resolve, reject) {
$.ajax({
url: url,
type: 'GET',
success: function (res) {
resolve(res)
},
error: function(err) {
reject('请求失败')
}
})
})
}; async function getDate() {
console.log('开始')
let result1 = await ajaxGet('data1.json');
let result2 = await ajaxGet(result1.url);
let result3 = await ajaxGet(result2.url);
console.log('result1 ---> ', result1); // result1 ---> {url: "data2.json"}
console.log('result2 ---> ', result2); // result2 ---> {url: "data3.json"}
console.log('result3 ---> ', result3); // result3 ---> {url: "this is data3.json"}
}; getDate(); // 需要执行异步函数

async await捕捉错误:

  • async await中.then(..)不用写了,那么.catch(..)也不用写,可以直接用标准的try catch语法捕捉错误。

例如,如果下面的 url 写错了

function ajaxGet (url) {
return new Promise(function (resolve, reject) {
$.ajax({
url: url111, // 此处为错误的 url
type: 'GET',
success: function (res) {
resolve(res)
},
error: function(err) {
reject('请求失败')
}
})
})
}; async function getDate() {
console.log('开始')
try {
let result1 = await ajaxGet('data1.json'); // 执行到这里报错,直接跳至下面 catch() 语句
let result2 = await ajaxGet(result1.url);
let result3 = await ajaxGet(result2.url);
console.log('result1 ---> ', result1);
console.log('result2 ---> ', result2);
console.log('result3 ---> ', result3); } catch(err) {
console.log(err) // ReferenceError: url111 is not defined
}
}; getDate(); // 需要执行异步函数

源码

源码查看

更多

请参考:

ES7 之 Async/await 的使用的更多相关文章

  1. ES7的Async/Await的简单理解

    Async/Await 的个人见解 正文: async,顾名思义,一个异步执行的功能,而 await 则是配合 async 使用的另一个关键字,也是闻字识其意,就是叫你等待啦! 二者配合食用效果更佳哦 ...

  2. 体验异步的终极解决方案-ES7的Async/Await

    阅读本文前,期待您对promise和ES6(ECMA2015)有所了解,会更容易理解.本文以体验为主,不会深入说明,结尾有详细的文章引用. 第一个例子 Async/Await应该是目前最简单的异步方案 ...

  3. ES7之async/await

    async 是 ES7 才有的与异步操作有关的关键字. async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数. async function helloAsync(){ ...

  4. ES7的async/await

    async 表示这是一个async函数,await只能用在这个函数里面. await 表示在这里等待promise返回结果了,再继续执行. await 后面跟着的应该是一个promise对象 awai ...

  5. 让webpack打包支持ES7的async/await语法

    npm install --save-dev babel-plugin-transform-runtime npm install --save babel-runtime .babelrc配置 { ...

  6. Promise及Async/Await

      一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪 ...

  7. NodeJs通过async/await处理异步

    ##场景 远古时代 我们在编写express后台,经常要有许多异步IO的处理.在远古时代,我们都是用chunk函数处理,也就是我们最熟悉的那种默认第一个参数是error的函数.我们来模拟一个Mongo ...

  8. 异步Promise及Async/Await最完整入门攻略

    一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪圈, ...

  9. promise 进阶 —— async / await 结合 bluebird

    一.背景 1.Node.js 异步控制 在之前写的 callback vs async.js vs promise vs async / await 里,我介绍了 ES6 的 promise 和 ES ...

随机推荐

  1. Android View体系(五)从源码解析View的事件分发机制

    1.处理点击事件的方法 View的层级 我们知道View的结构是树形的结构,View可以放在ViewGroup中,这个ViewGroup也可以放到另一个ViewGroup中,这样层层的嵌套就组成了Vi ...

  2. spring资源访问接口和资源加载接口

    spring 资源访问接口 JDK提供的资源访问类,如java.net.URL.File等,不能很好地满足各种资源的访问需求,比如缺少从类路径或者Web容器的上下文中获取资源的操作类. 鉴于此,spr ...

  3. C# 异步编程4 async与await 异步程序开发

    随着C#异步程序开发系列的深入,你会发现编写异步程序越发简单.事物的发展就是这样的规律,从简单到复杂再到简单. 在C# 5.0中我们可以通过async与await关键字实现快捷的异步程序开发,如下: ...

  4. git版本控制工具基本用法讲解(转)

    一.安装Git 在linux系统使用非常方便,只需要打开shell界面,并输入: ? 1 sudo apt-get install git-core 按下回车后输入密码,即可完成Git的安装.但我们可 ...

  5. 微信小程序のCss(一)

    一.margin:外边距:设置对象四边的外延边距. margin: 20rpx 10rpx 25rpx 10rpx :如果提供全部四个参数值,将按上.右.下.左的顺序作用于四边. margin:20r ...

  6. CentOS 7下安装Python3.6.4

    CentOS 7下安装Python3.5 •安装python3.6可能使用的依赖 yum install openssl-devel bzip2-devel expat-devel gdbm-deve ...

  7. chm文件转换成html文件,解决chm文件无法使用浏览器打开的问题

    每天学习一点点 编程PDF电子书免费下载: http://www.shitanlife.com/code CHM是英语“Compiled Help Manual”的简写,即“已编译的帮助文件”.CHM ...

  8. Codeforces Round #553 (Div. 2) D. Stas and the Queue at the Buffet 贪心+公式转化

    题意 给出n个pair (a,b) 把它放在线性序列上 1--n 上 使得  sum(a*(j-1)+b*(n-j))  最小 思路 :对式子进行合并 同类项 有:    j*(a-b)+  (-a+ ...

  9. Zabbix 3.4.2 install && Configuration

    原理: 1)zabbix server:负责接收agent发送的报告信息的核心组件,所有配置.统计数据及操作数据都由它组织进行: 2)database storage:专用于存储所有配置信息,以及由z ...

  10. Mybatis学习总结(三)——SqlMapConfig.xml全局配置文件解析

    经过上两篇博文的总结,对mybatis中的dao开发方法和流程基本掌握了,这一节主要来总结一下mybatis中的全局配置文件SqlMapConfig.xml在开发中的一些常用配置,首先看一下该全局配置 ...