做一个团购网站的成本,外国做刹车片的企业网站,企业所得税优惠政策最新2022文件,策划书范文案例原文链接#xff1a;Await and Async Explained with Diagrams and Examples文章目录简介Promise问题#xff1a;组合 PromiseAsync 函数Await错误处理讨论简介JavaScript ES7中的 async/await 使得协调异步 promise 变得更容易。如果你需要从多个数据库或 API 异步获取数据Await and Async Explained with Diagrams and Examples文章目录简介Promise问题组合 PromiseAsync 函数Await错误处理讨论简介JavaScript ES7中的 async/await 使得协调异步 promise 变得更容易。如果你需要从多个数据库或 API 异步获取数据则可以使用 promise 和回调函数。async / await 使我们更简洁地表达这种逻辑并完成更易读和可维护的代码。本教程将使用图表和简单示例来解释 JavaScript中 的 async / await 语法。在讲解之前我们从 promises 的简要概述开始。如果你已经了解了 JS 中的 promise请随时跳过本节。Promises在 JavaScript 中promise 代表非阻塞异步执行的抽象对象。JS中的 promise 与 Java 中的Future 或C的Task类似如果你了解它们的话那就很容易理解。Promise 通常用于网络和 I/O 操作例如读取文件或者发出 HTTP 请求。我们可以产生一个异步 promise 并使用 then 的方法来附加一个回调函数这个回调函数当 promise 完成时将会被触发这种方法不会阻止当前的“线程”执行。回调函数本身可以返回 promise使我们可以有效地链接 promises。为了容易理解在所有示例中我们假设 request-promise 库已经安装并加载为var rp require(request-promise);
我们做一个简单的 HTTP GET 请求返回一个promise:const promise rp(http://example.com/)
现在让我们来看一个例子console.log(Starting Execution);const promise rp(http://example.com/); // Line 3
promise.then(result console.log(result)); // Line 4console.log(Cant know if promise has finished yet...);
我们在第3行产生了一个新的 Promise然后在第4行新加一个回调函数。因为promise 是异步的所以当我们到达第6行时我们不知道 promise 是否已经完成。如果我们多次运行代码我们可能会每次得到不同的结果。换句话说任何 promise 之后的代码都是与 promise 同时运行的。在 promise 完成之前并没有办法阻止当前的操作顺序。 这与 Java 中的 Future.get 不同其允许我们阻止当前线程然后之后完成。在 JavaScript 中我们不能等待 promise。在 promise 之后调度代码的唯一方法是通过 then 附加回调函数。下图描绘了该示例的计算过程promise 的计算过程。呼叫“线程”不能等待 promise 。在 promise 之后调度代码的唯一方法是通过then方法指定回调函数。当 promise 成功返回时只有通过then方法指定回调函数才能执行。如果它失败了例如由于网络错误回调函数将不会执行。为了处理失败的 promise 你可以通过catch附加另一个回调函数rp(http://example.com/).then(() console.log(Success)).catch(e console.log(Failed: ${e}))
最后为了测试一下我们可以使用Promise.resolve和Promise.reject方法创建成功或失败的“虚拟”promises:const success Promise.resolve(Resolved);
// 将会显示 Successful result: Resolved
success.then(result console.log(Successful result: ${result})).catch(e console.log(Failed with: ${e}))const fail Promise.reject(Err);
// 将会显示 Failed with: Err
fail.then(result console.log(Successful result: ${result})).catch(e console.log(Failed with: ${e}))
有关 promises 的更详细的教程请查看这篇文章组合 Promise使用单一 Promise 是简单有效的。但是当我们需要对复杂的异步逻辑进行编程时我们可能会以组合多个 Promise。编写所有的子句和匿名回调可能很容易失控。例如假设我们需要编写一个程序进行HTTP请求等待完成打印结果;然后进行其他两个并行HTTP调用;当它们都完成时打印结果。 以下代码段演示了如何完成此操作//进行第一个调用
const call1Promise rp(http://example.com/); // Line 2call1Promise.then(result1 {//在第一个请求完成后执行console.log(result1);const call2Promise rp(http://example.com/); // Line 8const call3Promise rp(http://example.com/); // Line 9return Promise.all([call2Promise, call3Promise]); // Lin 11
}).then(arr { // Line 12//两个 promise 完成后执行console.log(arr[0]);console.log(arr[1]);
})
我们首先进行第一个 HTTP 调用并使用回调以在其完成时运行第1-3行。在回调中我们为后续的 HTTP 请求产生了两个 Promise第8-9行。这两个 Promise 同时运行并且我们需要安排一个回调当它们都完成时。因此当它们都执行完成时我们需要通过Promise.all第11行将它们组合成一个单一的 Promise。回调的结果是一个 Promise我们需要l连接另一个回调函数来打印结果行12-16。下图描述了计算流程计算过程中的 Promise 组合。我们使用“Promise.all”将两个并发的 Promise组合成一个 Promise。对于这样一个简单的例子我们最终得到了 2 个回调并且必须使用Promise.all来同步并发Promise。如果我们不得不再运行一些异步操作或添加错误处理怎么办这种方法最终很容易崩溃于then-sPromise.all调用和回调三者混杂在一起。Async异步函数是用于定义返回Promise的函数的快捷方式。 例如以下定义是等价的function f() {return Promise.resolve(TEST);
}// asyncF相当于f
async function asyncF() {return TEST;
}
类似地抛出异常的异步函数等效于返回拒绝 Promise 的函数function f() {return Promise.reject(Error);
}// asyncF相当于f
async function asyncF() {throw Error;
}
Await当我们使用 promise 之后我们只能通过then来传回回调函数(callback)。 不允许直接等待一个 promise 执行完毕是为了鼓励用户书写非阻塞的代码不然用户会更乐意写阻塞的代码因为它比 promise 和回调函数更简单。然而为了同步 promise, 我们需要允许 promise 之间相互等待。换句话说如果一个异步的操作(例如封装在一个 promise 中)就应该去等待另一个异步的操作去完成。但是 JavaScript 解释器如何判断一个操作是否在 promise 中运行呢答案就是 async 关键字。每一个 async 函数都会返回一个 promise。也就是说 JavaScript 解释器就会把所有在 aysnc 函数中的操作封装到 promise 中并异步运行。这样就可以让它们去等待其他的 promise 完成。按下 await 关键字await 只能在 async 函数中使用作用是让我们同步的等待另一个 promise 执行完毕。如果在 async 函数之外使用 promise 的话依旧需要使用 then 回调函数async function f() {// 返回值将作为 promise 被处理(resolve)之后的结果const response await rp(http://example.com/);console.log(response);
}
// 不能在 async 函数之外使用 await 关键字
// 需要使用 then 回调
f().then(() console.log(Finished));
现在来看看如何解决刚在在上面一节出现的问题// 将解决问题的方法封装到一个异步的函数中
async function solution() {// 等待第一个 HTTP 调用并且打印出结果console.log(await rp(http://example.com/));// 生成 HTTP 调用但是不等待它们执行完毕 - 同时运行const call2Promise rp(http://example.com/); // 不等待! // Line 7const call3Promise rp(http://example.com/); // 不等待! // Line 8//在它们都被调用之后 - 等待它们执行完毕const response2 await call2Promise; // Line 11const response3 await call3Promise; // Line 12console.log(response2);console.log(response3);
}// 调用 async 函数
solution().then(() console.log(Finished))
在上面的代码段中我们将解决方案封装到了一个 async 函数中这样我们就可以直接的等待(await) promise 执行完毕。这样避免了使用 then 回调函数。 最后我们调用了 async 函数这个函数只是简单的生成了一个封装调用其他 promise 的 promise。在第一个例子(没有 async 和 await)中那些 promise 会并行启动。这种情况下我们进行了同样的操作(第78行)。注意直到11到12行我们都没有使用 await。当所有的promise都执行完毕(resolve)我们才去阻塞程序的执行。之后我们知道两个 promise 都执行完毕了(就像在之前的例子中使用 Promise.all(...).then(...) 一样)。在底层的计算过程上这个过程和先前章节所述的过程是相同的但是代码更加直观可读性更好。在引擎中async/await 实际上转成了 promise 和 then传入的回调函数。换句话说它是 promise 的语法糖。每次我们使用 await解释器就会生成一个 promise然后把其余的操作从 async 函数取出来放到 then 传入的回调函数中。考虑一下下面的例子async function f() {console.log(Starting F);const result await rp(http://example.com/);console.log(result);
}
函数f在底层计算过程描述如下图。由于f是异步的它将和调用者同步运行函数f开始运行并且生成了一个promise。同时函数其余的部分被封装到回调函数中安排在promise执行完毕之后再执行。错误处理在前面几个例子中我们假设promise 成功的解决(reslove).于是等待一个promise返回结果。事实上如果等待的promise失败(reject)了那么async函数将会返回一个异常(exception)。我们可以使用标准的try/catch去处理这种情况async function f() {try{const promiseResult await Promise.reject(Error);} catch (e) {console.log(e);}
}
如果一个async函数没有处理异常不管它是一个被拒绝(reject)的promise还是其他的 bug 造成的它将返回一个被拒绝(reject)的promise:async function f() {// 抛出异常const promiseResult await Promise.reject(Error);
}// 将打印 Error
f().then(() console.log(Success)).catch(err console.log(err))async function g() {throw Error;
}// 将打印 “Error”
g().then(() console.log(Success)).catch(err console.log(err))
使用已知的异常处理机制将使我们方便的处理被拒绝(reject)的promise。讨论 Async/await是promises的一种补充语言结构。它允许我们使用较少样板的 promise。然而async/await不能取代纯粹 promise 的需要。例如如果从一个普通的函数或者全局范围内调用一个async函数我们无法使用await我们将借助于普通的promises(译者注原文使用的是vanilla promise):async function fAsync() {// 事实上返回值是 Promise.resolve(5)return 5;
}
// 不能调用 await fAsync(), 需要使用 then/catch
fAsync().then(r console.log(result is ${r}));
我通常尝试将我大部分的异步逻辑封装到一个或者几个 async 函数中然后从非异步的代码中调用。这极大地减少了我编写then/catch回调的数量。async/await 结构是更简洁处理 promise 的语法糖。每一个 async/await 结构都可以使用纯粹的 promise 重写。最终这是一个风格和简洁方面的问题。学者们指出并发( concurrency )和并行( parallelism )有区别。查看Rob Pike关于该主题或我之前的帖子。并发是关于组合独立进程在过程的一般含义中一起工作而并行是关于实际上同时执行多个进程。并发是关于应用程序的设计和结构而并行性就是实际的执行。以多线程应用程序为例。将应用程序分隔为线程定义其并发模型。这些线程在可用内核上的映射定义了其级别或并行。并发系统可以在单个处理器上有效运行在这种情况下它不是并行的。在这种情况下promise允许我们将程序分解为可并行运行的并发模块。实际的 JavaScript执行是否并行取决于 JavaScript 解释器实现。例如Node.js是单线程的如果 promise 是 CPU 绑定的那么并不会看到很多并行进程。然而如果您通过类似 Nashorn 的工具将代码编译成 java 字节码理论上你可以在不同的 CPU 核心上映射CPU绑定的 promise 并实现并行运行。因此在我看来promise普通或通过async/await构成了JavaScript应用程序的并发模型。文章转自 | Github文章链接 | 图解 Await 和 Async