Home Web Front-end JS Tutorial Simplify asynchronous code with Async functions (JavaScript development tips)

Simplify asynchronous code with Async functions (JavaScript development tips)

Apr 23, 2017 am 09:49 AM
async javascript asynchronous

Promise became popular on the Internet when it was first released on JavaScript - they help developers escape callback hell and solve the asynchrony problems that plague JavaScript developers in many places. But Promises are far from perfect. They keep requesting callbacks, can still be a bit messy and incredibly redundant on some complex issues.

With the arrival of ES6 (now called ES2015), in addition to the introduction of Promise specifications and no need to request countless libraries, we also have generators. Generators can stop execution inside a function, which means they can be wrapped in a multipurpose function and we can wait for the asynchronous operation to complete before moving to the next line of code. Suddenly your asynchronous code may start to look synchronous.

This is just the first step. Asynchronous functions have been standardized since they were added to ES2017 this year, and local support has been further optimized. The idea of ​​async functions is to use generators for asynchronous programming, giving them their own semantics and syntax. Therefore, you don't need to use a library to get the encapsulated utility functions, as these are handled behind the scenes.

To run the async/await example in the article, you need a compatible browser.

Running Compatibility

On the client side, Chrome, Firefox and Opera support asynchronous functions well.

Simplify asynchronous code with Async functions (JavaScript development tips)

Starting from version 7.6, Node.js async/await is enabled by default.

Comparison between asynchronous functions and generators

Here is an example of using a generator for asynchronous programming, using the Q library:

var doAsyncOp = Q.async(function* () { 
 
  var val = yield asynchronousOperation(); 
 
  console.log(val); 
 
  return val; 
 
});
Copy after login

Q .async is a wrapper function that handles things after the scene. Where * represents the function as a generator function, yield represents the stop function and is replaced by a wrapper function. Q.async will return a function that you can assign a value to, just like doAsyncOp, and then call it.

The new syntax in ES7 is more concise, the operation example is as follows:

async function doAsyncOp () { 
 
  var val = await asynchronousOperation();      
 
  console.log(val); 
 
  return val; 
 
};
Copy after login

The difference is not big, wedeletean encapsulated function and* symbol, use the async keyword instead. The yield keyword has also been replaced by await. These two examples actually do the same thing: after the asynchronousOperation is completed, assign the value to val, then output and return the result.

Convert Promises into asynchronous functions

What would the previous example look like if we used Vanilla Promises?

function doAsyncOp () { 
 
  return asynchronousOperation().then(function(val) { 
 
    console.log(val); 
 
    return val; 
 
  }); 
 
};
Copy after login

The same here lines of code, but this is because then and the callback function passed to it add a lot of extra code. Another annoyance are the two return keywords. This has always been something that bothered me, because it's hard to figure out what exactly a function using promises returns.

As you can see, this function returns a promise, which will be assigned to val. Guess what the generator and async function examples do! No matter what you return in this function, you are secretly Return a promise that resolves to that value. If you return no value at all, the promise you return implicitly resolves to undefined.

Chained operations

One of the reasons why Promise is so popular is that it can connect multiple asynchronous operations in a chained call, avoiding embedded callbacks. . But async functions are even better than Promise in this regard.

The following demonstrates how to use Promise to perform chain operations (we simply run asynchronousOperation multiple times to demonstrate).

function doAsyncOp() { 
 
  return asynchronousOperation() 
 
    .then(function(val) { 
 
      return asynchronousOperation(val); 
 
    }) 
 
    .then(function(val) { 
 
      return asynchronousOperation(val); 
 
    }) 
 
    .then(function(val) { 
 
      return asynchronousOperation(val); 
 
    }); 
 
}
Copy after login

To use the async function, you only need to call asynchronousOperation like writing synchronous code:

async function doAsyncOp () { 
 
  var val = await asynchronousOperation(); 
 
  val = await asynchronousOperation(val); 
 
  val = await asynchronousOperation(val); 
 
  return await asynchronousOperation(val); 
 
};
Copy after login

You don’t even need to use it in the final return statement Await, whether used or not, returns a Promise that contains a handleable final value.

Concurrent operations

Promise has another great feature, they can perform multiple asynchronous operations at the same time, and wait for them all to complete before continuing Others event. The ES2015 specification provides Promise.all(), which is used to do this.

Here is an example:

function doAsyncOp() { 
 
  return Promise.all([ 
 
    asynchronousOperation(), 
 
    asynchronousOperation() 
 
  ]).then(function(vals) { 
 
    vals.forEach(console.log); 
 
    return vals; 
 
  }); 
 
}
Copy after login

Promise.all() can also be used as an async function:

async function doAsyncOp() { 
 
  var vals = await Promise.all([ 
 
    asynchronousOperation(), 
 
    asynchronousOperation() 
 
  ]); 
 
  vals.forEach(console.log.bind(console)); 
 
  return vals; 
 
}
Copy after login

Even if Promise.all is used here, the code is still clear.

Handling rejection

Promises 可以被接受(resovled)也可以被拒绝(rejected)。被拒绝的 Promise 可以通过一个函数来处理,这个处理函数要传递给 then,作为其第二个参数,或者传递给 catch 方法。现在我们没有使用 Promise API 中的方法,应该怎么处理拒绝?可以通过 try 和 catch 来处理。使用 async 函数的时候,拒绝被当作错误来传递,这样它们就可以通过 JavaScript 本身支持的错误处理代码来处理。

function doAsyncOp() { 
 
  return asynchronousOperation() 
 
    .then(function(val) { 
 
      return asynchronousOperation(val); 
 
    }) 
 
    .then(function(val) { 
 
      return asynchronousOperation(val); 
 
    }) 
 
    .catch(function(err) { 
 
      console.error(err); 
 
    }); 
 
}
Copy after login

 

这与我们链式处理的示例非常相似,只是把它的最后一环改成了调用 catch。如果用 async 函数来写,会像下面这样。

async function doAsyncOp () { 
 
  try { 
 
    var val = await asynchronousOperation(); 
 
    val = await asynchronousOperation(val); 
 
    return await asynchronousOperation(val); 
 
  } catch (err) { 
 
    console.err(err); 
 
  } 
 
};
Copy after login

 

它不像其它往 async 函数的转换那样简洁,但是确实跟写同步代码一样。如果你在这里不捕捉错误,它会延着调用链一直向上抛出,直到在某处被捕捉处理。如果它一直未被捕捉,它最终会中止程序并抛出一个运行时错误。Promise 以同样的方式运作,只是拒绝不必当作错误来处理;它们可能只是一个说明错误情况的字符串。如果你不捕捉被创建为错误的拒绝,你会看到一个运行时错误,不过如果你只是使用一个字符串,会失败却不会有输出。

中断 Promise

拒绝原生的 Promise,只需要使用 Promise 构建函数中的 reject 就好,当然也可以直接抛出错误——在 Promise 的构造函数中,在 then 或 catch 的回调中抛出都可以。如果是在其它地方抛出错误,Promise 就管不了了。

这里有一些拒绝 Promise 的示例:

function doAsyncOp() { 
 
  return new Promise(function(resolve, reject) { 
 
    if (somethingIsBad) { 
 
      reject("something is bad"); 
 
    } 
 
    resolve("nothing is bad"); 
 
  }); 
 
} 
 
  
 
/*-- or --*/ 
 
  
 
function doAsyncOp() { 
 
  return new Promise(function(resolve, reject) { 
 
    if (somethingIsBad) { 
 
      reject(new Error("something is bad")); 
 
    } 
 
    resolve("nothing is bad"); 
 
  }); 
 
} 
 
  
 
/*-- or --*/ 
 
  
 
function doAsyncOp() { 
 
  return new Promise(function(resolve, reject) { 
 
    if (somethingIsBad) { 
 
      throw new Error("something is bad"); 
 
    } 
 
    resolve("nothing is bad"); 
 
  }); 
 
}
Copy after login

 

一般来说,最好使用 new Error,因为它会包含错误相关的其它信息,比如抛出位置的行号,以及可能会有用的调用栈。

这里有一些抛出 Promise 不能捕捉的错误的示例:

function doAsyncOp() { 
 
  // the next line will kill execution 
 
  throw new Error("something is bad"); 
 
  return new Promise(function(resolve, reject) { 
 
    if (somethingIsBad) { 
 
      throw new Error("something is bad"); 
 
    } 
 
    resolve("nothing is bad"); 
 
  }); 
 
} 
 
  
 
// assume `doAsyncOp` does not have the killing error 
 
function x() { 
 
  var val = doAsyncOp().then(function() { 
 
    // this one will work just fine 
 
    throw new Error("I just think an error should be here"); 
 
  }); 
 
  // this one will kill execution 
 
  throw new Error("The more errors, the merrier"); 
 
  return val; 
 
}
Copy after login

 

在 async 函数的 Promise 中抛出错误就不会产生有关范围的问题——你可以在 async 函数中随时随地抛出错误,它总会被 Promise 抓住:

async function doAsyncOp() { 
 
  // the next line is fine 
 
  throw new Error("something is bad"); 
 
  if (somethingIsBad) { 
 
    // this one is good too 
 
    throw new Error("something is bad"); 
 
  } 
 
  return "nothing is bad"; 
 
}  
 
  
 
// assume `doAsyncOp` does not have the killing error 
 
async function x() { 
 
  var val = await doAsyncOp(); 
 
  // this one will work just fine 
 
  throw new Error("I just think an error should be here"); 
 
  return val; 
 
}
Copy after login

 

当然,我们永远不会运行到 doAsyncOp 中的第二个错误,也不会运行到 return 语句,因为在那之前抛出的错误已经中止了函数运行。

问题

如果你刚开始使用 async 函数,需要小心嵌套函数的问题。比如,如果你的 async 函数中有另一个函数(通常是回调),你可能认为可以在其中使用 await ,但实际不能。你只能直接在 async 函数中使用 await 。

比如,这段代码无法运行:

async function getAllFiles(fileNames) { 
 
  return Promise.all( 
 
    fileNames.map(function(fileName) { 
 
      var file = await getFileAsync(fileName); 
 
      return parse(file); 
 
    }) 
 
  ); 
 
}
Copy after login

 

第 4 行的 await 无效,因为它是在一个普通函数中使用的。不过可以通过为回调函数添加 async 关键字来解决这个问题。

async function getAllFiles(fileNames) { 
 
  return Promise.all( 
 
    fileNames.map(async function(fileName) { 
 
      var file = await getFileAsync(fileName); 
 
      return parse(file); 
 
    }) 
 
  ); 
 
}
Copy after login

 

你看到它的时候会觉得理所当然,即便如此,仍然需要小心这种情况。

也许你还想知道等价的使用 Promise 的代码:

function getAllFiles(fileNames) { 
 
  return Promise.all( 
 
    fileNames.map(function(fileName) { 
 
      return getFileAsync(fileName).then(function(file) { 
 
        return parse(file); 
 
      }); 
 
    }) 
 
  ); 
 
}
Copy after login

 

接下来的问题是关于把 async 函数看作同步函数。需要记住的是,async 函数内部的的代码是同步运行的,但是它会立即返回一个 Promise,并继续运行外面的代码,比如:

var a = doAsyncOp(); // one of the working ones from earlier 
 
console.log(a); 
 
a.then(function() { 
 
  console.log("`a` finished"); 
 
}); 
 
console.log("hello"); 
 
  
 
/* -- will output -- */ 
 
Promise Object 
 
hello 
 
`a` finished
Copy after login

 

你会看到 async 函数实际使用了内置的 Promise。这让我们思考 async 函数中的同步行为,其它人可以通过普通的 Promise API 调用我们的 async 函数,也可以使用它们自己的 async 函数来调用。

如今,更好的异步代码!

即使你本身不能使用异步代码,你也可以进行编写或使用工具将其编译为 ES5。 异步函数能让代码更易于阅读,更易于维护。 只要我们有 source maps,我们可以随时使用更干净的 ES2017 代码。

有许多可以将异步功能(和其他 ES2015+功能)编译成 ES5 代码的工具。 如果您使用的是 Babel,这只是安装 ES2017 preset 的例子。

The above is the detailed content of Simplify asynchronous code with Async functions (JavaScript development tips). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1662
14
PHP Tutorial
1262
29
C# Tutorial
1235
24
How to implement an online speech recognition system using WebSocket and JavaScript How to implement an online speech recognition system using WebSocket and JavaScript Dec 17, 2023 pm 02:54 PM

How to use WebSocket and JavaScript to implement an online speech recognition system Introduction: With the continuous development of technology, speech recognition technology has become an important part of the field of artificial intelligence. The online speech recognition system based on WebSocket and JavaScript has the characteristics of low latency, real-time and cross-platform, and has become a widely used solution. This article will introduce how to use WebSocket and JavaScript to implement an online speech recognition system.

WebSocket and JavaScript: key technologies for implementing real-time monitoring systems WebSocket and JavaScript: key technologies for implementing real-time monitoring systems Dec 17, 2023 pm 05:30 PM

WebSocket and JavaScript: Key technologies for realizing real-time monitoring systems Introduction: With the rapid development of Internet technology, real-time monitoring systems have been widely used in various fields. One of the key technologies to achieve real-time monitoring is the combination of WebSocket and JavaScript. This article will introduce the application of WebSocket and JavaScript in real-time monitoring systems, give code examples, and explain their implementation principles in detail. 1. WebSocket technology

How to use JavaScript and WebSocket to implement a real-time online ordering system How to use JavaScript and WebSocket to implement a real-time online ordering system Dec 17, 2023 pm 12:09 PM

Introduction to how to use JavaScript and WebSocket to implement a real-time online ordering system: With the popularity of the Internet and the advancement of technology, more and more restaurants have begun to provide online ordering services. In order to implement a real-time online ordering system, we can use JavaScript and WebSocket technology. WebSocket is a full-duplex communication protocol based on the TCP protocol, which can realize real-time two-way communication between the client and the server. In the real-time online ordering system, when the user selects dishes and places an order

How to implement an online reservation system using WebSocket and JavaScript How to implement an online reservation system using WebSocket and JavaScript Dec 17, 2023 am 09:39 AM

How to use WebSocket and JavaScript to implement an online reservation system. In today's digital era, more and more businesses and services need to provide online reservation functions. It is crucial to implement an efficient and real-time online reservation system. This article will introduce how to use WebSocket and JavaScript to implement an online reservation system, and provide specific code examples. 1. What is WebSocket? WebSocket is a full-duplex method on a single TCP connection.

JavaScript and WebSocket: Building an efficient real-time weather forecasting system JavaScript and WebSocket: Building an efficient real-time weather forecasting system Dec 17, 2023 pm 05:13 PM

JavaScript and WebSocket: Building an efficient real-time weather forecast system Introduction: Today, the accuracy of weather forecasts is of great significance to daily life and decision-making. As technology develops, we can provide more accurate and reliable weather forecasts by obtaining weather data in real time. In this article, we will learn how to use JavaScript and WebSocket technology to build an efficient real-time weather forecast system. This article will demonstrate the implementation process through specific code examples. We

Simple JavaScript Tutorial: How to Get HTTP Status Code Simple JavaScript Tutorial: How to Get HTTP Status Code Jan 05, 2024 pm 06:08 PM

JavaScript tutorial: How to get HTTP status code, specific code examples are required. Preface: In web development, data interaction with the server is often involved. When communicating with the server, we often need to obtain the returned HTTP status code to determine whether the operation is successful, and perform corresponding processing based on different status codes. This article will teach you how to use JavaScript to obtain HTTP status codes and provide some practical code examples. Using XMLHttpRequest

JavaScript and WebSocket: Building an efficient real-time image processing system JavaScript and WebSocket: Building an efficient real-time image processing system Dec 17, 2023 am 08:41 AM

JavaScript is a programming language widely used in web development, while WebSocket is a network protocol used for real-time communication. Combining the powerful functions of the two, we can create an efficient real-time image processing system. This article will introduce how to implement this system using JavaScript and WebSocket, and provide specific code examples. First, we need to clarify the requirements and goals of the real-time image processing system. Suppose we have a camera device that can collect real-time image data

How to get HTTP status code in JavaScript the easy way How to get HTTP status code in JavaScript the easy way Jan 05, 2024 pm 01:37 PM

Introduction to the method of obtaining HTTP status code in JavaScript: In front-end development, we often need to deal with the interaction with the back-end interface, and HTTP status code is a very important part of it. Understanding and obtaining HTTP status codes helps us better handle the data returned by the interface. This article will introduce how to use JavaScript to obtain HTTP status codes and provide specific code examples. 1. What is HTTP status code? HTTP status code means that when the browser initiates a request to the server, the service

See all articles