Mongoose 中调用 callback 函数后仍然返回 promise 对象

阅读时长 5 分钟读完

背景

Mongoose 是 Node.js 中使用最广泛的操作 MongoDB 数据库的库之一。在使用 Mongoose 进行数据库操作的过程中,我们常常需要使用到 callback 函数来获取返回的结果,例如查询数据时:

然而,在现代 JavaScript 开发中,我们更倾向于使用 Promise 对象来处理异步操作,因为它更加灵活方便、易于组合等。因此,一些库(比如 axios)已经开始默认返回 Promise 对象,而不是 callback 函数。

在 Mongoose 中,虽然原生的操作接口都是基于 callback 函数的,但是它提供了一种方法可以将 callback 函数转化为 Promise 对象,即使用 exec() 方法。

显然,使用 exec() 方法可以大大简化代码的书写,使其看起来更加简洁。然而,你可能会有这样一个疑问:调用完 exec() 方法后,我们得到的是一个 Promise 对象,而不是像原生方法那样的结果。那么,这个 Promise 对象到底是由谁返回的呢?Promise 接口是如何实现的?

解析

事实上,Mongoose 在调用 exec() 方法后返回的 Promise 对象是它内部所实现的。Mongoose 中的所有操作方法(包括查询、更新、删除等等)都支持对应的 exec() 方法,用于将 callback 函数转化为 Promise 对象。这个方法的内部实现如下:

-- -------------------- ---- -------
-------------------- - -------- ---- --------- -
  --- ----- - -----
  --- ------- - --- ---------------- --------- ------- -
    -------- - -------------------- -
      -------- --------
      ------- ------
    -- ----------
    --- -
      --- ---------------- - ---------------------- -- ---
      ------------------- - ---
      --------------------------------------------
    - ----- ------- -
      ----------------
    -
  ---
  -- ---------------------- -
    ------- - -----------------------------------
  -
  ------ --------
--
展开代码

首先,它会创建一个 Promise 对象,并将 resolve 和 reject 方法保留下来,以便在回调函数中调用。

然后,它会使用 _wrapCallback() 方法将原始的 callback 函数封装起来,并在内部调用 resolve 和 reject 方法,这样就可以将结果通过 Promise 接口返回给调用方。

最后,它会将 promise 对象的 read() 方法绑定到 this._readPreference 上,以支持读写分离等特性。

指导意义

这样的设计带来了什么好处呢?

首先,使用 Promise 真正实现了异步编程的语义,而不是使用回调函数层层嵌套,从而使代码更易于阅读和理解。如果你曾经使用过回调函数,那么你一定深刻体会到通过回调函数处理异步操作时代码的复杂度和难以维护性。

其次,使用 Promise 可以更好地支持代码重用和封装,因为 Promise 对象支持链式调用,可以将多个步骤组合在一起,形成一个完整的操作流程,而不必嵌套多层回调函数。

最后,使用 Promise 也能更好地支持错误处理和调试,因为 Promise 对象支持类似 try-catch 的异常捕获机制,可以将错误信息统一处理,避免出现未处理的异常终止程序运行。

示例代码

下面是一个简单的 Mongoose 查询操作的例子,它使用 exec() 方法将 callback 函数转化为 Promise 对象。

-- -------------------- ---- -------
----- -------- - --------------------

-------------------------------------------- - ---------------- ---- ---

----- ---------- - --- -----------------
  ----- -------
  ---- ------
---

----- ---- - ---------------------- ------------

--------------- ----- -----
    ---------------   -- -------
    -------------     -- -- --- --
    ---------         -- --- -- ---
    ---------         -- ---- - ---
    -------
    ------------ -- --------------------
    ------------ -- ---------------------
    ----------- -- -----------------------
展开代码

通过使用 exec() 方法,我们可以轻松地连接多个操作,从而实现复杂的查询需求,并使用 Promise 接口处理返回结果。

结论

在 Mongoose 中调用 callback 函数后仍然返回 Promise 对象的原因是 exec() 方法将 callback 函数封装为 Promise 对象,从而使用 Promise 接口处理异步操作,使代码更容易理解和维护,同时也支持更好的代码封装和错误处理机制。因此,建议在使用 Mongoose 进行数据库操作时尽量使用 exec() 方法,以便更好地兼容现代 JavaScript 的开发模式。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/675369a48bd460d3ada51c78

纠错
反馈

纠错反馈