摘要:和的关系和的关系非常的巧妙,必须在内使用,并装饰一个对象,返回的也是一个对象。的会使得的代码节点自动抛出相应的异常,终止向下继续执行。示例方法内无节点没有修饰的方法内有节点注意内的对节点的作用。
假设我们有三个请求,req1,req2, req3,三个请求后者依赖前者的请求结果。我们先使用Promise封装一个异步请求的方法。
Promise 异步请求使用Promise可以非常容易的封装一个异步处理的业务,通过reslove/reject两个callback来返回执行结果。
我们使用 Promise 封装一个 http get方法。
// 返回一个 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对象有关系呢?
回调地狱Promise 可以优雅的实现异步,但 Promise.then().catch() 的链式结构也带来了回调地狱的问题。如下,我们回调了3层,才能开始写业务逻辑。
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) })async/await
借助 aysnc/await 解决回调地狱的问题,实现同步风格的异步逻辑,这里希望大家能理解透2 & 3两条总结:
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(" ") } 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对象,所以我们还可以继续使用 asyncawait封装异步到同步风格。
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(" ") } catch (err) { // Promise reject throw err } } getUrlsMore(url, url).then(res => { console.log(res) }).catch(err => { console.log(err) })async/await 和 Promise 的关系
async/await 和 Promise 的关系非常的巧妙,await必须在async内使用,并装饰一个Promise对象,async返回的也是一个Promise对象。
async/await中的return/throw会代理自己返回的Promise的resolve/reject,而一个Promise的resolve/reject会使得await得到返回值或抛出异常。
如果方法内无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
注意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(" ") } 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) })
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/110298.html
摘要:但是中的这种情况与抽象反应器模式如何描述完全不同。在处理一个阶段之后并且在移到下一个队列之前,事件循环将处理两个中间队列,直到中间队列中没有剩余的项目。如果没有任务则循环退出,每一次队列处理都被视为事件循环的一个阶段。 Promise && async/await的理解和用法 为什么需要promise(承诺)这个东西 在之前我们处理异步函数都是用回调这个方法,回调嵌套的时候会发现 阅读...
摘要:最近项目中用的比较多,所以特地去了解,模仿一下实现先来看看使用的方法通过是通过使用生成器配合方法模拟的一个同步操作,这个技术有效的避免了传统回调和形成的回调地狱。 最近项目中 asyn & await 用的比较多,所以特地去了解,模仿一下实现~ 先来看看 使用 async & await 的方法 async function d () { try { const a = a...
摘要:的出现,让我们可以走出回调地狱,着实惊艳。我已经开始使用里的和关键字来简化的处理。异步任务在这个例子是执行之后,一直在执行完成才继续下一个任务并没有产生阻塞。最后这个函数处理了返回值并且返回了一个对象。依然很棒,但和使得它可维护性更好。 JavaScript Promises的出现,让我们可以走出回调地狱,着实惊艳。Promises 允许我们更好的引入和处理异步任务,虽然如此,但引入好...
摘要:但是提出标准,允许脚本创建多个线程,但是子线程完全受主线程控制。只是将事件插入了任务队列,必须等到当前代码执行栈执行完,主线程才会去执行它指定的回调函数。之后全局上下文进入函数调用栈。 setTimeout 一、setTimeout 初现 定义:setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。 语法: setTimeout(code, millisec...
摘要:前文该系列下的前几篇文章分别对不同的几种异步方案原理进行解析,本文将介绍一些实际场景和一些常见的面试题。流程调度里比较常见的一种错误是看似串行的写法,可以感受一下这个例子判断以下几种写法的输出结果辨别输出顺序这类题目一般出现在面试题里。 前文 该系列下的前几篇文章分别对不同的几种异步方案原理进行解析,本文将介绍一些实际场景和一些常见的面试题。(积累不太够,后面想到再补) 正文 流程调度...
阅读 2217·2021-09-30 09:47
阅读 962·2021-08-27 13:01
阅读 2963·2019-08-30 15:54
阅读 3688·2019-08-30 15:53
阅读 827·2019-08-29 14:07
阅读 714·2019-08-28 18:16
阅读 797·2019-08-26 18:37
阅读 1407·2019-08-26 13:27