假设咱们有三个请求,req1,req2, req3,三个请求后者依赖前者的请求结果。咱们先使用Promise
封装一个异步请求的方法。html
使用Promise
能够很是容易的封装一个异步处理的业务,经过reslove/reject
两个callback
来返回执行结果。promise
咱们使用 Promise
封装一个 http get
方法。dom
// 返回一个 Promise 对象(PromiseStatus: pending) function asyncHttpGet(url) { return new Promise((resolve, reject) => { const request = new Request(url, {method: 'GET'}) // 使用 fetch 请求 fetch(request) .then(response => { if (200 == response.status) { return response.text() } else { // goto catch throw new Error("request failed: " + response.status) } }).then(html => { // console.log(html) resolve(url + " get success") }).catch(err => { reject(err) }); }) }
fetch
返回的其实就是一个Promise
对象,上例是想演示下resolve/reject
的使用上下文,若是你早已get
,下面给出直接使用fetch
的方式:异步
async function asyncHttpGetV2(url) { const request = new Request(url, {method: 'GET'}) try { let res = await fetch(request) .then(response => response.blob()) .then(blob => { console.log(blob) // Promise resolve return blob }).catch(err => { // Promise resolve throw err }); // Promise resolve return res; } catch (err) { // Promise reject throw err } }
能够发现,fetch
中return
代替了resolve
,throw
代替了reject
,而async
同fetch
同样,也是返回了一个 Promise
对象,因此async
中的return/throw
是否也会与本身的返回的Promise
对象有关系呢?async
Promise
能够优雅的实现异步,但 Promise.then().catch()
的链式结构也带来了回调地狱的问题。以下,咱们回调了3层,才能开始写业务逻辑。fetch
var url = window.location.href // 虽然异步了 但 callback hell asyncHttpGet(url).then(res => { var res1 = res asyncHttpGet(url).then(res => { var res2 = res asyncHttpGet(url).then(res => { var res3 = res console.log(res1, res2, res3); // todo 业务 }).catch(err => { console.log(err) }) }).catch(err => { console.log(err) }) }).catch(err => { console.log(err) })
借助 aysnc/await
解决回调地狱的问题,实现同步风格的异步逻辑,这里但愿你们能理解透2 & 3
两条总结:url
aysnc
返回的也是一个 Promise
对象。return 标量
或 throw Error
则返回 {PromiseStatus: resolved/rejected}
的 Promise
对象。await
装饰的Promise
,则返回 {PromiseStatus: pending}
的 Promise
。并等待此Promise
的执行结果:若是Promise
触发了resolve
则获取结果并继续向下执行;若是Promise
触发了reject
则抛出一个异常。因此咱们在使用时应将代码使用try...catch
封装。await
关键字只能在 async
内使用,await
主要意图是装饰一个以 {PromiseStatus: pending}
的状态返回的Promise
对象(任何 JS 表达式均可以,但没什么意义),并等待其后续的resolved/rejected
状态更新,从而决定是得到结果并继续向下执行,仍是终止并抛出异常。var url = window.location.href async function getUrls(url1, url2, url3) { try { // req1 success or throw error (promise reject) let res1 = await asyncHttpGet(url1); // req2 success or throw error (promise reject) let res2 = await asyncHttpGet(url2); // req3 success or throw error (promise reject) let res3 = await asyncHttpGet(url3); // 三个异步请求都成功 获取最终结果 return [res1, res2, res3].join("\n") } catch(err) { // 出现错误,作一些处理 console.log(err) throw err } } // 如此 3 个 Promise 请求在 async/await 的封装下变成了一个同步书写风格的异步请求 getUrls(url, url, url).then(res => { console.log(res) // todo 业务 }).catch(err => { console.log(err) }) console.log("request has been sended, and waiting for res")
async 返回的是 Promise
对象,因此咱们还能够继续使用 async\await
封装异步到同步风格。spa
async function getUrlsMore(url1, url2) { try { let getUrls1 = await getUrls(url1, url1, url1) let getUrls2 = await getUrls(url2, url2, url2) // Promise resolve return [getUrls1, getUrls2].join("\n") } catch (err) { // Promise reject throw err } } getUrlsMore(url, url).then(res => { console.log(res) }).catch(err => { console.log(err) })
async/await
和 Promise
的关系很是的巧妙,await
必须在async
内使用,并装饰一个Promise
对象,async
返回的也是一个Promise
对象。代理
async/await
中的return/throw
会代理本身返回的Promise
的resolve/reject
,而一个Promise
的resolve/reject
会使得await
获得返回值或抛出异常。code
若是方法内无await
节点
return
一个字面量
则会获得一个{PromiseStatus: resolved}
的Promise
。throw
一个Error
则会获得一个{PromiseStatus: rejected}
的Promise
。
若是方法内有await
节点async
会返回一个{PromiseStatus: pending}
的Promise
(发生切换,异步等待Promise
的执行结果)。Promise
的resolve
会使得await
的代码节点得到相应的返回结果,并继续向下执行。Promise
的reject
会使得await
的代码节点自动抛出相应的异常,终止向下继续执行。
示例:
await
节点// 没有 await 修饰的 Promise async function foo() { if (Math.ceil(Math.random() * 10) > 5) { // {PromiseStatus: resolved} return "hello world" } else { // {PromiseStatus: rejected} throw new Error("something wrong!") } } var fooPromise = foo() console.log(fooPromise) fooPromise.then(res => { console.log(res) }).catch(err => { console.log(err) })
resolved
rejected
await
节点注意Promise
内的resolve/reject
对 await
节点的做用。
async function bar() { try { // await 返回 {PromiseStatus: pending} let res = await new Promise((resolve, reject) => { setTimeout(() => { if (Math.ceil(Math.random() * 10) > 5) { // await 得到结果并继续执行 resolve("success") } else { // await 中断执行并抛出异常 reject("failed") } }, 2000) }) // resolve {PromiseStatus: resolved} return res } catch (err) { // reject {PromiseStatus: rejected} throw err } } var barPromise = bar() // 查看 barPromise 的 PromiseStatus console.log(barPromise) barPromise.then(res => { console.log(res) }).catch(err => { console.log(err) })
await
配合fetch
的实例then/catch
返回的也是Promise
对象,在then/catch
内使用return/throw
来决定返回的Promise
是resolved/rejected
。
// 没有 await 修饰的 Promise async function bar() { try { // await 返回 {PromiseStatus: pending} let res1 = await fetch(window.location.href).then(res => { if (200 == res.status) { // Promise resolve return "request success" } else { // goto catch throw "request failed" + res.status } }).catch(err => { // Promise reject throw err }) let res2 = await fetch(window.location.href).then(res => { if (200 == res.status) { // Promise resolve return "request success" } else { // goto catch throw "request failed" + res.status } }).catch(err => { // Promise reject throw err }) let res3 = await fetch(window.location.href).then(res => { if (200 == res.status) { // Promise resolve return "request success" } else { // goto catch throw "request failed" + res.status } }).catch(err => { // Promise reject throw err }) // 三个请求都成功 则返回相应的数据 Promise resolved return [res1, res2, res3].join("\n") } catch (err) { // Promise rejected throw err } } var barPromise = bar() // 查看 barPromise 的 PromiseStatus console.log(barPromise) // Promise reject 抛出异常 须要使用 catch 捕捉 barPromise.then(res => { console.log(res) }).catch(err => { console.log(err) })