簡體   English   中英

NodeJS中的異步等待(嘗試/捕獲)

[英]async await (try/catch) in NodeJS

我正在研究 NodeJS API,我想知道ROUTES 文件中的以下 2 個示例中哪一個是最佳實踐。 正如您在一個中看到的那樣,我正在添加 try/catch,而在另一個中我沒有。 請注意,在Service.js文件中,我也添加了 try/catch。 我是只在一個地方需要它還是在兩個地方都使用它更好?

路線文件

 const todo = router => {
      /* EXAMPLPE 1 */
      router.get('/tasks', isAuth, async (req, res, next) => {
        const results = await TodoService.getTasks();
        return res.status(201).json(results);
      });

      /* EXAMPLPE 2 */
      router.get('/tasks', isAuth, async (req, res, next) => {
        try {
           const results = await TodoService.getTasks();
           return res.status(201).json(results);
         } catch (e) {
             return next(e);
         }
      };

服務.JS

class TodoService {
  static async getTasks() {
    try {
      const tasks = await TaskModel.find();
      return {
        message: 'Fetched posts successfully.',
        tasks: tasks,
        status: 200
      };
    } catch (err) {
      if (!err.statusCode) {
        err.statusCode = 500;
      }
      return err;
    }
  }
}

在您的問題的現在編輯版本中, getTasks()永遠不能拒絕其 promise (因為您發現任何可能的拒絕並將它們變成已解決的承諾)。 因此,示例 2 中的調用者包含一個完全沒有意義的try/catch ,它基本上是永遠無法使用的死代碼。 雖然看起來它可能是更安全的代碼,但它基本上是浪費的代碼。

在 function 的文檔/合同中明確說明它是否可以拒絕。 如果不能,那么調用者就沒有理由嘗試處理拒絕,因為那只是毫無意義的代碼。

就個人而言,我認為讓錯誤通過被拒絕的 promise 回流可能更靈活,因為它可以在更多地方使用並且更容易與其他操作結合使用。 但是,如果唯一的目的是作為請求處理程序的一個部分,那么它可能會保存代碼以集中拒絕捕獲並將其轉換為解析的 object,然后像現在一樣返回。 對於不同類型的調用者不太靈活,但如果調用 function 的目的總是很窄,則可能更簡單的代碼來集中拒絕捕獲。

沒有正確/錯誤的答案。 這主要取決於您最想優化的內容(靈活的調用者使用與集中式錯誤捕獲)和您的個人風格偏好。

不幸的是,在我寫下這個答案之后,OP 編輯了他們的問題以使其有所不同。 此答案已寫入問題的原始版本。

兩者都可以正常工作,這真的是一個見仁見智的問題。

首先,您確保方法調用永遠不會返回被拒絕的 promise,因此您不必在調用者中捕獲拒絕。

在第二種情況下,您可以返回一個被拒絕的 promise,因此您必須在調用者中捕獲拒絕。

就個人而言,每當我看到一個沒有任何代碼的await時,它看起來就像一個編碼錯誤,所以你必須很好地記錄該方法從不拒絕。 我個人認為如果錯誤拒絕並且調用者可以決定做什么,它會更靈活。 這允許該方法被更廣泛的調用者使用,但確實需要調用者捕獲拒絕。

另一方面,如果 function 的所有可能用途都在請求處理程序中,您所要做的就是返回沒有拒絕的狀態,以便可以將狀態作為響應發送回,那么您可能通過捕獲來節省代碼錯誤集中在 function 中,而不是在每個調用者中。

就像我說的,這主要是編碼風格偏好的問題。 您只需確保在某處處理任何可能的 promise 拒絕,以便始終對傳入請求發送適當的響應。

這里的概念是有效的,但這是偽代碼,我沒有運行它。 另外,“引號”中的任何術語都不是正確的術語

使用 try catch 開發層次結構時要記住的重要一點是錯誤總是拋出三個。 因此,您應該始終確保您有一個最高級別的 try catch 以處理錯誤。

在您可能在服務中引發錯誤並在路由中處理它的情況下,您的服務最好保留為“純功能”以趕上更高的水平。 我發現這會下意識地讓你避免循環依賴 如果您想拋出自定義錯誤,您可能會在兩個“級別”上使用 try/catch。

一個例子是:

// Router
Router.get('/tasks', async (req, res) => {
    try { 
        return await TodoService.getTasksById(taskId);
    } catch (err) {
        return errorResponseUtility(err.status, err.message);
    }
}

// Service
const getTasksById = async id => {
    try {
        return await DB()
            .connect('tasks')
            .select('*')
            .where({ id });
    } catch (err) {
        if(err instanceOf NotFoundError) throw err;
    }
}

// Error Defs
const NotFoundError = {
    status: 404,
    message: 'Resource could not be found'
}

這樣,如果您沒有任何錯誤,但以正確的方式與隨機 502

其他:解構你的 req.params:

const { id: taskId } = req.params; // This renames id to taskId

或者,不要解構它,直接解析它,因為它只使用一次。

所以答案取決於代碼風格。 Javascript 有很多結構代碼的方法。 您的第一個選項更接近使用箭頭 function 的功能樣式,第二個選項是使用 ES2015 中引入的 class 設置。

但是,只有第一個實際創建了路由器。 因此,您仍然需要將 TodoService 中的 map 您的 static 方法編碼到 URL。

來自 Java 的開發人員會發現基於 class 的代碼更易於遵循。 有在快遞中提供小型服務經驗的人可能會發現第一個示例更容易理解。

作為開發人員,我個人的偏好是盡可能簡單地在日志中調用 map API 調用代碼。 我喜歡 express 的一件事是使用嵌套路由器和中間件是多么容易。

所以對我來說,你的第一個很接近。 我只是沒有任何匿名函數。 相反,這些函數應該在一個外部文件中,可能是routes.js ,並且設置好以便您可以輕松地對它們進行單元測試。

例如

路由.js

function makeTaskRoute = function(TodoService) {
 return async getTasks(req, res, next) => {
    const results = await TodoService.getTasks();
    return res.status(201).json(results);
 }
}

module.exports = {
  makeTaskRoute
}

然后在 index.js

const TodoService = require('todo/service/TodoService.js');
const getTasks = require('./routes/routes.js').makeTaskRoute(TodoService);
const router = express.Router()

router.get('/tasks', getTasks);

這是一種更實用的風格,但也允許依賴注入和簡單的測試。

要使這個更清潔,還有更多工作要做,而且很多都是偏好。 但我發現這一點(加上在 typescript 中使用聲明的類型並干凈地分離出數據結構和突變)是干凈的、易於閱讀的、易於維護和改進的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM