编程语言
首页 > 编程语言> > 如何在 Node 中使用各种异步模式与数据库交互

如何在 Node 中使用各种异步模式与数据库交互

作者:互联网

JavaScript 有一个语句。这部分很简单:运行一些代码并捕获异常,以便可以优雅地处理它们。但是我们为什么需要?提供一种运行清理代码的方法,无论 OR 块中是否引发异常。清理代码通常包括关闭文件句柄和数据库连接。try…catch…finallytry…catchfinallyfinallytrycatch

下面是一个示例:

1
try {

2
  console.log('try 1');

3
  throw new Error('foo');

4
  console.log('try 2');

5
} catch (err) {

6
  console.log('catch 1', err);

7
  throw new Error('bar');

8
  console.log('catch 2');

9
} finally {

10
  console.log('finally!');

11
}

如果您在浏览器控制台(或 Node.js 中运行它),您应该在控制台中看到如下所示的内容:

1
try 1

2
catch 1 Error: foo

3
    at <anonymous>:3:9

4
finally!

5
Uncaught Error: bar

6
    at <anonymous>:7:9

请注意,块中引发的异常最终会作为未经处理的异常冒泡,但不是在执行块之前。barcatchfinally

如果我们在 Node.js 中运行的所有代码都是同步的,我们将能够执行以下操作:

1
try {

2
  // get a connection to the DB

3
  // use the connection to do work

4
} catch (error) {

5
  // handle the error

6
} finally {

7
  // close the connection

8
}

不幸的是,它对异步代码不是很有用—— 至少在异步函数可用之前是这样。原因与 Node.js 中异步工作的方式有关。try…catch…finally

异步/事件处理

下面概述了如何执行异步操作,例如发出 HTTP 请求和执行数据库查询。

 

你所有的JavaScript代码都在主线程上运行。异步 API 从主线程和传递的回调函数调用。根据类型,异步工作可能会完全发生,或者可能会利用线程池。异步工作完成后,回调函数将添加到回调队列中,以尽快在主线程上调用。

使用此体系结构,异步处理期间发生的错误将返回到完全不同的调用堆栈中的主线程。您无法捕获不同调用堆栈中引发的错误 - 为时已晚!

下面是调用异步 API 的一个非常简单的演示:

1
setTimeout(function() {

2
  console.log('hello');

3
}, 2000);

4

5
console.log('world');

如果在浏览器控制台或 Node.js 中运行该脚本,则输出将为:

1
world

2
hello

在“hello”之前两秒看到“世界”可能会让异步编程新手感到惊讶。使其工作的秘诀是传递给 的回调函数。它将“回调”,或者在指定的时间过后在主线程上执行。setTimeout

回调函数可以追溯到 JavaScript 的起源,JavaScript 被设计为一种为网络带来生命的语言。JavaScript 开发人员需要一种将代码与事件相关联的方法,例如加载页面、单击鼠标或按下键盘上的键。随着时间的推移,引入了如下 DOM API。

1
window.addEventListener('load', function() {

2
  // do some work

3
});

上面的方法将传入的匿名函数作为第二个参数,并将其添加到与元素上的事件相关的侦听器列表中。事件发生时,所有侦听器都会添加到回调队列中,并会尽快被调用。addEventListenerloadwindow

为了使回调正常工作,JavaScript 中的函数需要一些重要的特性:它们需要是一等对象,并且需要闭包。

功能一流

函数作为第一类对象的概念听起来比实际更复杂。大多数编程语言都提供了一种声明变量和创建命名代码单元(通常称为函数或过程)的方法。这两种构造之间通常有明显的区别。例如,可以声明变量并将其传递给函数,但不能将函数传递到函数中。

另一方面,JavaScript允许函数更像标准数据类型,如数字,字符串和布尔值。函数可以声明,从一个函数传递到另一个函数,并在将来的某个时候调用。将函数视为一类对象是将回调函数传递到另一个函数的先决条件,但该功能也有助于代码组织。

假设您希望在加载页面和用户单击窗口时执行相同的代码。你可以做这样的事情:

1
window.addEventListener('load', function() {

2
  // do some work

3
});

4

5
window.addEventListener('click', function() {

6
  // do the same work here

7
});

上面代码的问题在于,我们必须维护两个执行相同工作的函数。但是,知道函数是一等对象,我们可以声明一个命名函数,并根据需要传递对它的引用:

1
function doWork() {

2
  // do some work

3
}

4

5
window.addEventListener('load', doWork);

6
window.addEventListener('click', doWork);

如您所见,函数作为一类对象是 JavaScript 的一个简单但强大的功能。

功能提供闭合

闭包的概念一开始可能有点难以理解——但它对于异步/事件编程至关重要。简而言之,闭包是一个函数,它引用在其封闭作用域中定义的变量。

许多语言允许开发人员在函数中嵌套函数,子函数可以引用在父函数的作用域中声明的变量。使用其他语言的开发人员可能永远不会想,“如果在父函数完成执行后运行时调用子函数,会发生什么情况?这根本不可能。但 JavaScript 并非如此!

请记住,JavaScript 中的函数是一等对象,因此与分配给变量的任何其他值一样,它们可以通过传递来摆脱父函数的限制。发生这种情况时,对原始封闭作用域(词法作用域)中的变量的引用仍然存在。那么,将来调用子函数时会发生什么?

闭包可确保只要运行时可能需要调用子函数,子函数就能够访问这些变量。这些变量不会像往常那样被垃圾回收。

下面是一个闭包示例:

1
<html>

2
  <body>

3
    <button id="my-button">Click me!</button>

4

5
    <script>

6
    function onLoad() { // "onLoad" is the parent function.

7
      var button = document.getElementById('my-button');

8

9
      function onClick() { // "onClick" is the child function (closure).

10
        button.parentNode.removeChild(button); // "button" referes to the enslosing scope.

11
      }

12

13
      // "onClick" can be invoked after "onLoad" finishes but the reference to "button"

14
      // will still be valid thanks to closure.

15
      button.addEventListener('click', onClick);

16
    }

17

18
    window.addEventListener('load', onLoad);

19
    </script>

20
  </body>

21
</html>

您可以将此代码复制并粘贴到扩展名为.html的文件中,然后在浏览器中打开它。您应该会看到一个按钮,上面写着“单击我!当窗口加载时,该函数使用按钮上的事件注册函数。onLoadonClickclick

请注意,未在 中调用 。相反,引用被传递给将来可以调用该函数的 API。由于引用在(父)函数中声明的变量,因此闭包可确保将来何时调用该变量。onClickonLoadonClickbuttononLoadonClickbutton

现在我们已经解决了与 JavaScript 中的异步编程相关的一些核心概念,让我们把注意力转向 Node.js 中发展的一些异步模式。

常见异步模式

目前,用于使用 Node 编写异步代码的最常见(和通用)模式.js是回调、异步模块和 promise。Node.js v7.6 对 V8 JavaScript 引擎进行了更新,引入了一种称为异步函数的异步处理新方法。

在为生成器和承诺所做的工作之上,异步函数允许在异步执行时同步编写 JavaScript 代码。最重要的是,循环等同步结构可以按照您的期望工作!异步函数是 JavaScript 的一个重大游戏规则改变者,但对承诺的了解,以及一般的异步处理,仍然很重要。try…catch…finally

我将介绍的每个模式都将有一个专门的帖子。每篇文章都将解释该模式的基础知识,并提供使用该模式的演示应用程序。演示应用将执行相同的三个异步操作:获取与数据库的连接,使用它执行简单查询,然后关闭连接。

要在本地运行演示应用程序,假设已安装 Node.js 和 OCI 客户端库,只需克隆相关的 Gist 或在目录中创建各种文件即可。接下来,在终端中打开目录并运行,然后运行 .npm installnode index.js

提示:如果您想设置本地沙盒来完成这些示例,请参阅此博客文章。

以下是每种模式的链接(随着系列新帖子的发布,链接将变为活动状态):

标签:Node,JavaScript,数据库
来源: