authors are vetted experts in 的ir fields 和 write on topics in which 的y have demonstrated experience. All of our content is peer reviewed 和 validated by Toptal experts in 的 same field.
Demir Selmanovic
验证专家 在工程
24 的经验

Demir is a developer 和 project manager with over 15 years of professional experience in a wide range of software development roles.

分享

One of 的 keys to writing a successful web application is being able to make dozens of AJAX calls per page.

这是一个典型的异步编程挑战, 以及如何选择处理异步调用, 很大程度上, 成就或破坏你的应用, 延伸到整个创业公司.

Synchronizing 异步hronous tasks in JavaScript was a serious issue for a very long time.

这一挑战正在影响后端 使用节点的开发人员.js as much as front-end developers using 任何 JavaScript framework. 异步 programming is a part of our everyday work, but 的 challenge is often taken lightly 和 not considered at 的 right time.

异步JavaScript简史

The first 和 的 most straightforward solution came in 的 form of 嵌套函数作为回调函数. 这个解决方案产生了一种叫做 回调地狱,还有太多的应用程序仍然感受到它的灼热.

然后,我们得到 承诺. 这种模式使代码更容易阅读, but it was a far cry from 的 Don’t Repeat Yourself (DRY) principle. There were still too m任何 cases where you had to repeat 的 same pieces of code to properly manage 的 application’s flow. The latest addition, in 的 form of 异步/等待 JavaScript 语句, finally made JavaScript异步代码 像其他代码一样易于阅读和编写.

Let’s take a look at 的 examples of each of 的se solutions 和 reflect on 的 evolution of 异步hronous programming in JavaScript.

要做到这一点, our 异步hronous JavaScript tutorial will examine a simple task that performs 的 following steps:

  1. 验证用户的用户名和密码.
  2. 获取用户的应用程序角色.
  3. 记录用户的应用程序访问时间.

方法1:回调地狱(“末日金字塔”)

The ancient solution to synchronize 的se calls was via nested callbacks. This was a decent approach for simple 异步hronous JavaScript tasks, 但由于一个叫做 回调地狱.

Illustration: 异步 JavaScript 回调地狱 anti-pattern

The code for 的 three simple tasks would look something like this:

const verifyUser = function(username, password, callback){
   数据库.verifyUser(username, password, (error, userInfo) => {
       If (error) {
           回调(错误)
       其他}{
           数据库.将getRoles(username, (error, roles) => {
               如果(错误){
                   回调(错误)
               其他}{
                   数据库.logAccess(username, (error) => {
                       如果(错误){
                           回调(错误);
                       其他}{
                           callback(null, userInfo, roles);
                       }
                   })
               }
           })
       }
   })
};

Each function gets an argument which is ano的r function that is called with a parameter that is 的 response of 的 previous action.

Too m任何 people will experience brain freeze just by reading 的 sentence above. Having an application with hundreds of similar code blocks will cause even more trouble to 的 person maintaining 的 code, 即使是他们自己写的.

This example gets even more complicated once you realize that a 数据库.将getRoles 另一个函数有嵌套回调吗.

const 将getRoles =函数(用户名,回调){
   数据库.connect((连接) => {
       连接.query('get roles sql', (result) => {
           回调(零,结果);
       })
   });
};

In addition to having code that is difficult to maintain, DRY原则在这种情况下绝对没有价值. 错误处理, 例如, is repeated in each function 和 的 main callback is called from each nested function.

更复杂的异步JavaScript操作, 例如通过异步调用进行循环, 是更大的挑战吗. In fact, 的re is no trivial way of doing this with callbacks. 这就是为什么JavaScript承诺库喜欢 蓝知更鸟Q 得到了如此多的关注. They provide a way to perform common operations on 异步hronous requests that 的 language itself doesn’t already provide.

这就是原生JavaScript承诺的用武之地.

JavaScript的承诺

承诺 逃离回调地狱的下一个合乎逻辑的步骤是什么. 此方法没有删除回调的使用, but it made 的 chaining of 异步hronous functions in JavaScript straightforward 和 简化代码使它更容易阅读.

插图:异步JavaScript承诺图

有了承诺, 的 code in our 异步hronous JavaScript example would look something like this:

const verifyUser = function(用户名,密码){
   数据库.verifyUser(用户名、密码)
       .然后(userInfo => 数据库.将将getRoles(用户信息)
       .然后(rolesInfo => 数据库.logAccess (rolesInfo))
       .然后(finalResult => {
           //执行'callback'将要执行的操作
       })
       .抓((err) => {
           //执行错误处理程序所需的任何操作
       });
};

To achieve this kind of simplicity, all of 的 functions used in 的 example would have to be Promisified. 让我们来看看 将getRoles 方法将被更新为返回 承诺:

const 将getRoles = function (username){
   return new 承诺((解决, 拒绝) => {
       数据库.connect((连接) => {
           连接.query('get roles sql', (result) => {
               解决(结果);
           })
       });
   });
};

我们修改了这个方法以返回a 承诺,有两个回调,以及 承诺 自身执行方法中的操作. 现在, 解决拒绝 回调函数将被映射到 承诺.然后承诺.抓 方法分别.

你可能会注意到 将getRoles method is still internally prone to 的 pyramid of doom phenomenon. This is due to 的 way 数据库 methods are created as 的y do not return 承诺. 如果我们的数据库访问方法也返回 承诺将getRoles 方法如下所示:

const 将getRoles = new function (userInfo) {
   return new 承诺((解决, 拒绝) => {
       数据库.connect ()
           .然后((连接) => 连接.查询('get roles sql')
           .然后((result) => 解决(result))
           .抓住(拒绝)
   });
};

方法3:Async/Await

The pyramid of doom was significantly mitigated with 的 introduction of 承诺. However, we still had to rely on callbacks that are passed on to .然后.抓 a的方法 承诺.

承诺 paved 的 way to one of 的 coolest improvements in JavaScript. ECMAScript 2017 brought in syntactic sugar on top of 承诺 in JavaScript in 的 form of 异步等待 语句.

他们允许我们写作 承诺基于的代码,就好像它是同步的, 但是不会阻塞主线程, 如下代码示例所示:

const verifyUser = 异步函数(用户名,密码){
   尝试{
       const userInfo =等待数据库.verifyUser(用户名、密码);
       const rolesInfo =等待数据库.将将getRoles(用户信息);
       const logStatus =等待数据库.logAccess(用户信息);
       返回用户信息;
   }捕捉(e) {
       //根据需要处理错误
   }
};

等待 承诺 只有在内心才允许解决 异步 函数的意思是 verifyUser 必须使用 异步函数.

然而,一旦做了这个小小的改变,你就可以 等待 任何 承诺 无需对其他方法进行额外更改.

Async JavaScript - A Long Awaited Resolution of a 承诺

Async functions are 的 next logical step in 的 evolution of 异步hronous programming in JavaScript. They will make your code much cleaner 和 easier to maintain. 将函数声明为 异步 将确保它总是返回 承诺 所以你不用再担心这个了.

什么 异步 do in JavaScript 和 why you should start using JavaScript 异步 今天的功能?

  1. 生成的代码要干净得多.
  2. 错误处理要简单得多,它依赖于 试一试/ 就像在其他同步代码中一样.
  3. 调试要简单得多. 类中设置断点 .然后 块不会移动到下一个 .然后 因为它只步进同步代码. 但是,你可以跳过 等待 调用,就好像它们是同步调用一样.

了解基本知识

  • 什么是异步和等待?

    Async/等待 语句 are syntactic sugar created on top of JavaScript的承诺. 他们允许我们写作 承诺基于的代码,就好像它是同步的, 但是不会阻塞主线程.

  • 什么是回调地狱?

    在JavaScript中, 回调地狱 is an anti-pattern in code that happens as a result of poor structuring of 异步hronous code. It is usually seen when programmers 试一试 to force a visual top-down structure in 的ir 异步hronous callback-based JavaScript code.

  • JavaScript的承诺是什么?

    A promise in JavaScript is like a placeholder value that is expected to eventually 解决 into 的 final successful result value or reason for failure.

聘请Toptal这方面的专家.
现在雇佣
Demir Selmanovic

Demir Selmanovic

验证专家 在工程
24 的经验

Sarajevo, Federation of Bosnia 和 Herzegovina, Bosnia 和 Herzegovina

2014年7月8日加入

作者简介

Demir is a developer 和 project manager with over 15 years of professional experience in a wide range of software development roles.

authors are vetted experts in 的ir fields 和 write on topics in which 的y have demonstrated experience. All of our content is peer reviewed 和 validated by Toptal experts in 的 same field.

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.