javascript 异步
One of the most powerful features of javascript is its ability to execute code asynchronously. Most of the programming languages are designed in such a way that the code is executed as soon as it is found. Asynchronous execution simply means that a piece of code is executed at a later point of time when a certain asynchronous task is performed. This asynchronous task could be anything:
javascript的最强大功能之一是其异步执行代码的能力。 大多数编程语言的设计方式都是在找到代码后立即执行。 异步执行仅意味着在执行某个异步任务时在以后的时间点执行一段代码。 这个异步任务可以是任何东西:
- A countdown from a timer ended 计时器倒计时结束
- A user performed a specific action 用户执行了特定操作
- An API call returned the data API调用返回了数据
回调函数:旧方法 (Call back functions: The old way)
One of the early ways to handle async operations was to provide an anonymous callback function which could be executed once the task was completed. While this looks like a quick and easy solution, it leads to confusion when we have to deal with multiple callbacks, nested one inside another.
处理异步操作的早期方法之一是提供一个匿名回调函数,该任务一旦完成就可以执行。 尽管这看起来是一种快速简便的解决方案,但当我们不得不处理多个嵌套在另一个内部的回调时,这会引起混乱。
const makePizza = () => {
getDough(function(dough) {
getCheese(dough, function(cheese) {
bakePizza(dough, cheese, function(pizza) {
return pizza;
})
})
})
}makePizza();
//Callback Hell
This is what programmers call the CallBack Hell
. The nested loop of anonymous functions to be executed one after another increases the complexity of the code. We can however try to reduce this complexity to some extent by modularizing the code. Here's an example of how this could be achieved.
这就是程序员所说的CallBack Hell
。 要依次执行的匿名函数的嵌套循环会增加代码的复杂性。 但是,我们可以通过对代码进行模块化来在某种程度上降低这种复杂性。 这是如何实现此目的的示例。
const makePizza = (nextStep) => {
pizza = nextStep(getCheese);
}function getDough(nextStep) {
const dough = getDoughFromShelf();
nextStep(dough, bakePizza);
}function getCheese(dough, nextStep) {
const cheese = getCheeseFromShelf();
nextStep(dough, cheese)
}function bakePizza(dough, cheese) {
const pizza = makePizza(dough, cheese);
return pizza;
}makePizza(getDough);
While this can be used to solve the problem of callback hell, if there are too many operations nested, this list of functions becomes hard to maintain. ES6 provided an easier way to deal with callback hell with the introduction of Promises
.
虽然这可以用来解决回调地狱的问题,但是如果嵌套的操作太多,则此函数列表将变得难以维护。 通过引入Promises
ES6提供了一种更轻松的方法来处理回调地狱。
承诺:统一处理嵌套回调 (Promises: Deal with nested callbacks flatly)
ES6 provides promises to deal with callback functions. By using then
and chaining the nested functions, we can provide a list of anonymous callback functions to execute in the given order.
ES6提供了处理回调函数的承诺 。 通过使用then
并链接嵌套函数,我们可以提供匿名回调函数列表,以指定顺序执行。
function makePizza() {
const pizza = getDough())
.then((dough) => getCheese(dough))
.then((dough, cheese) => bakePizza(dough, cheese)); return pizza;
}
makePizza();
We can also write functions to be executed and pass them as parameters to then
. This would ensure the reusability of code. While this provides a neat way of dealing with async operations, we can still see that the functions chained one after another, and it is hard to debug the data coming from these callbacks.
我们还可以编写要执行的函数,并将其作为参数传递给then
。 这将确保代码的可重用性。 尽管这提供了一种处理异步操作的巧妙方法,但是我们仍然可以看到这些函数彼此链接,并且很难调试来自这些回调的数据。
异步等待:处理异步任务的新方法 (Async Await: The new way to handle asynchronous tasks)
ES2017 introduced asynchronous functions. With this, our call back functions can be labeled async
, and these functions can be called with await
keyword just like calling synchronous functions. However, the change here is that the next line of code will be executed only after the async
function returns data or errors out.
ES2017引入了异步功能。 这样,我们的回调函数可以标记为async
,并且可以像调用同步函数一样使用await
关键字来调用这些函数。 但是,此处的更改是仅在async
函数返回数据或错误后才执行下一行代码。
async function makePizza() {
const dough = await getDough();
const cheese = await getCheese(dough);
const pizza = await bakePizza(dough, cheese);
return pizza;
}makepizza();
The functions getDough
, getCheese
and bakePizza
should be defined as async
functions. The makePizza function executes each await
operation and stops the rest of the execution until the operation/function returns any data.
函数getDough
, getCheese
和bakePizza
应该定义为async
函数。 makePizza函数将执行每个await
操作,并停止其余执行,直到该操作/函数返回任何数据。
并行执行异步功能 (Parallel execution of asynchronous functions)
So far we have seen that the asynchronous functions are executed one after another in the order in which they are called. However, in some cases, we might want to execute asynchronous functions parallelly because their execution doesn’t depend on each other.
到目前为止,我们已经看到异步函数按照它们被调用的顺序一个接一个地执行。 但是,在某些情况下,我们可能希望并行执行异步函数,因为它们的执行不相互依赖。
Promise.all: Promise.all() can be used to execute async functions parallelly.
Promise.all :Promise.all()可用于并行执行异步功能。
const asyncFunction = () => {
return new Promise((resolve) => {
console.log("I am executed parallelly")
setTimeout(resolve, 1000)
})
}const promise1 = asyncFunction();
const promise2 = asyncFunction();Promise.all([promise1, promise2]).then(() => {
console.log("I am executed in the end");
});
When you execute the above code, the asyncFunction
is called at the same time, and the function exits after the setTimeout is completed.
当您执行上述代码时, asyncFunction
将同时被调用,并且在setTimeout完成后函数将退出。
async-await: async-await can also be used for parallel execution of functions.
async-await :async-await也可以用于并行执行功能。
const asyncFunction = () => {
return new Promise((resolve) => {
console.log("I am executed parallelly")
setTimeout(resolve, 1000);
})
}async function parallel() {
const await1 = asyncFunction();
const await2 = asyncFunction();
await await1;
await await2; console.log("I am executed in the end");
}parallel();
The await1
and await2
holds the promise returned by the asyncFuntion
. Note that the function execution won't stop the flow. The await
keyword stops the follow and waits until the async
function has returned. In the above example, both the functions are fired at the same time, and hence they are parallelly executed.
await1
和await2
保留await2
返回的asyncFuntion
。 请注意,函数执行不会停止流程。 关键字await
停止跟踪,并等待直到async
函数返回。 在上面的示例中,两个函数同时触发,因此它们并行执行。
处理异步操作中的错误 (Handling errors in asynchronous operations)
Asynchronous operations are usually performed to get the data from an external resource. This has an enormous chance of failure due to a variety of reasons. The errors given by the async operations must be handled properly.
通常执行异步操作以从外部资源获取数据。 由于各种原因,这有很大的失败机会。 异步操作给出的错误必须得到正确处理。
Using catch in promises: Just like the Promises provide
then
to chain the callback functions and get the data from the asynchronous operation, they also provide acatch
block. This can be used to catch the error returned during execution. Note that if there are severalthen
operations chained together, the firsterror
will call thecatch
block and stop further execution.使用catch Promise :就像Promises提供
then
链接回调函数并从异步操作获取数据一样,它们也提供catch
块。 这可以用来捕获执行期间返回的错误。 请注意,如果有多个then
链接在一起的操作,则第一个error
将调用catch
块并停止进一步执行。
function makePizza() {
const pizza = getDough())
.then((dough) => getCheese(dough))
.then((dough, cheese) => bakePizza(dough, cheese))
.catch((err) => console.log(err)); return pizza;
}
makePizza();
If getDough() fails, the
catch
block is executed immediately. The chainedthen
callbacks won't be executed.如果getDough()失败,则立即执行
catch
块。 链式then
回调将不会被执行。If getDough() is successful, the next
then
block is executed.如果getDough()成功,则执行下一个
then
块。
Using try-catch block: This is the more popular and common way to handle errors in asynchronous operations. The piece of code executing the async function will be wrapped inside a
try-catch
block. Any error will stop further execution and immediately jump to catch block使用try-catch块 :这是处理异步操作中的错误的更流行和常用的方法。 执行异步功能的代码段将包装在
try-catch
块中。 任何错误将停止进一步执行,并立即跳转到catch块
async function makePizza() {
let pizza;
try {
const dough = await getDough();
const cheese = await getCheese(dough);
pizza = await bakePizza(dough, cheese);
} catch(err) {
console.log(err);
} return pizza;
}makepizza();
承诺v / s异步功能: (Promises v/s Asynchronous functions:)
The Asynchronous functions provided with ES2017 are not a replacement for the promises. Asynchronous functions are simply an alternative to the promises. When several callbacks could be nested, async functions provide a better, cleaner way of handling code. We can use both of these implementations in the code depending upon the coding standards used. Since asynchronous functions are provided with ES2017, certain browsers might not fully support it, and a polyfill might be required.
ES2017提供的异步功能不能替代承诺。 异步功能只是对Promise的替代。 当可以嵌套多个回调时,异步函数提供了一种更好,更简洁的代码处理方式。 根据所使用的编码标准,我们可以在代码中同时使用这两种实现。 由于ES2017提供了异步功能,因此某些浏览器可能不完全支持它,因此可能需要使用polyfill。
Originally published at https://aparnajoshi.netlify.app.
最初发布在 https://aparnajoshi.netlify.app上 。
翻译自: https://medium.com/swlh/javascript-async-operations-make-your-web-dynamic-d46b8c5f7042
javascript 异步