激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - node.js - nodejs的錯誤處理過程記錄

nodejs的錯誤處理過程記錄

2022-03-01 16:32the gc node.js

這篇文章主要給大家介紹了關于nodejs的錯誤處理過程的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

本文以連接錯誤ECONNREFUSED為例,看看nodejs對錯誤處理的過程。 假設我們有以下代碼

?
1
2
1.  const net = require('net'); 
2.  net.connect({port: 9999})

如果本機上沒有監聽9999端口,那么我們會得到以下輸出。

?
1
2
3
4
5
6
7
8
9
10
1.  events.js:170 
2.        throw er; // Unhandled 'error' event 
3.        ^ 
4.   
5.  Error: connect ECONNREFUSED 127.0.0.1:9999 
6.      at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1088:14) 
7.  Emitted 'error' event at: 
8.      at emitErrorNT (internal/streams/destroy.js:91:8) 
9.      at emitErrorAndCloseNT (internal/streams/destroy.js:59:3) 
10.     at processTicksAndRejections (internal/process/task_queues.js:81:17)

我們簡單看一下connect的調用流程。

?
1
2
3
4
5
6
7
8
1.  const req = new TCPConnectWrap(); 
2.  req.oncomplete = afterConnect; 
3.  req.address = address; 
4.  req.port = port; 
5.  req.localAddress = localAddress; 
6.  req.localPort = localPort; 
7.  // 開始三次握手建立連接 
8.  err = self._handle.connect(req, address, port);

接著我們看一下C++層connect的邏輯

?
1
2
3
4
1.  err = req_wrap->Dispatch(uv_tcp_connect, 
2.                               &wrap->handle_, 
3.                               reinterpret_cast<const sockaddr*>(&addr), 
4.                               AfterConnect);

C++層直接調用Libuv的uv_tcp_connect,并且設置回調是AfterConnect。接著我們看libuv的實現。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1.  do
2.      errno = 0; 
3.      // 非阻塞調用 
4.      r = connect(uv__stream_fd(handle), addr, addrlen); 
5.    } while (r == -1 && errno == EINTR); 
6.    // 連接錯誤,判斷錯誤碼 
7.    if (r == -1 && errno != 0) { 
8.      // 還在連接中,不是錯誤,等待連接完成,事件變成可讀 
9.      if (errno == EINPROGRESS) 
10.       ; /* not an error */
11.     else if (errno == ECONNREFUSED) 
12.       // 連接被拒絕 
13.       handle->delayed_error = UV__ERR(ECONNREFUSED); 
14.     else
15.       return UV__ERR(errno); 
16.   } 
17.   uv__req_init(handle->loop, req, UV_CONNECT); 
18.   req->cb = cb; 
19.   req->handle = (uv_stream_t*) handle; 
20.   QUEUE_INIT(&req->queue); 
21.   // 掛載到handle,等待可寫事件 
22.   handle->connect_req = req; 
23.   uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);

我們看到Libuv以異步的方式調用操作系統,然后把request掛載到handle中,并且注冊等待可寫事件,當連接失敗的時候,就會執行uv stream_io回調,我們看一下Libuv的處理(uv stream_io)。

?
1
2
3
4
5
6
7
8
1.  getsockopt(uv__stream_fd(stream), 
2.                 SOL_SOCKET, 
3.                 SO_ERROR, 
4.                 &error, 
5.                 &errorsize); 
6.  error = UV__ERR(error); 
7.  if (req->cb) 
8.      req->cb(req, error);

獲取錯誤信息后回調C++層的AfterConnect。

?
1
2
3
4
5
6
7
8
9
1.  Local<Value> argv[5] = { 
2.     Integer::New(env->isolate(), status), 
3.     wrap->object(), 
4.     req_wrap->object(), 
5.     Boolean::New(env->isolate(), readable), 
6.     Boolean::New(env->isolate(), writable) 
7.   }; 
8.   
9.   req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv);

接著調用JS層的oncomplete回調。

?
1
2
3
4
5
6
7
8
9
10
11
1.  const ex = exceptionWithHostPort(status, 
2.                                   'connect'
3.                                   req.address, 
4.                                   req.port, 
5.                                   details); 
6.  if (details) { 
7.    ex.localAddress = req.localAddress; 
8.    ex.localPort = req.localPort; 
9.  } 
10. // 銷毀socket 
11. self.destroy(ex);

exceptionWithHostPort構造錯誤信息,然后銷毀socket并且以ex為參數觸發error事件。我們看看uvExceptionWithHostPort的實現。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1.  function uvExceptionWithHostPort(err, syscall, address, port) { 
2.    const [ code, uvmsg ] = uvErrmapGet(err) || uvUnmappedError; 
3.    const message = `${syscall} $[code]: ${uvmsg}`; 
4.    let details = ''
5.   
6.    if (port && port > 0) { 
7.      details = ` ${address}:${port}`; 
8.    } else if (address) { 
9.      details = ` ${address}`; 
10.   } 
11.   const tmpLimit = Error.stackTraceLimit; 
12.   Error.stackTraceLimit = 0; 
13.   const ex = new Error(`${message}${details}`); 
14.   Error.stackTraceLimit = tmpLimit; 
15.   ex.code = code; 
16.   ex.errno = err; 
17.   ex.syscall = syscall; 
18.   ex.address = address; 
19.   if (port) { 
20.     ex.port = port; 
21.   } 
22.   // 獲取調用棧信息但不包括當前調用的函數uvExceptionWithHostPort,注入stack字段到ex中 
23.   Error.captureStackTrace(ex, excludedStackFn || uvExceptionWithHostPort); 
24.   return ex; 
25. }

我們看到錯誤信息主要通過uvErrmapGet獲取

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.  function uvErrmapGet(name) { 
2.    uvBinding = lazyUv(); 
3.    if (!uvBinding.errmap) { 
4.      uvBinding.errmap = uvBinding.getErrorMap(); 
5.    } 
6.    return uvBinding.errmap.get(name); 
7.  } 
8.   
9.  function lazyUv() { 
10.   if (!uvBinding) { 
11.     uvBinding = internalBinding('uv'); 
12.   } 
13.   return uvBinding; 
14. }

繼續往下看,uvErrmapGet調用了C++層的uv模塊的getErrorMap。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1.  void GetErrMap(const FunctionCallbackInfo<Value>& args) { 
2.    Environment* env = Environment::GetCurrent(args); 
3.    Isolate* isolate = env->isolate(); 
4.    Local<Context> context = env->context(); 
5.   
6.    Local<Map> err_map = Map::New(isolate); 
7.    // 從per_process::uv_errors_map中獲取錯誤信息 
8.    size_t errors_len = arraysize(per_process::uv_errors_map); 
9.    // 賦值 
10.   for (size_t i = 0; i < errors_len; ++i) { 
11.      // map的鍵是 uv_errors_map每個元素中的value,值是name和message
12.     const auto& error = per_process::uv_errors_map[i]; 
13.     Local<Value> arr[] = {OneByteString(isolate, error.name), 
14.                           OneByteString(isolate, error.message)};
15.     if (err_map 
16.             ->Set(context, 
17.                   Integer::New(isolate, error.value), 
18.                   Array::New(isolate, arr, arraysize(arr))) 
19.             .IsEmpty()) { 
20.       return
21.     } 
22.   } 
23.  
24.   args.GetReturnValue().Set(err_map); 
25. }

我們看到錯誤信息存在per_process::uv_errors_map中,我們看一下uv_errors_map的定義。

?
1
2
3
4
5
6
7
8
9
10
11
1.  struct UVError {
2.    int value;
3.    const char* name;
4.    const char* message;
5.  };
6. 
7.  static const struct UVError uv_errors_map[] = { 
8.  #define V(name, message) {UV_##name, #name, message}, 
9.      UV_ERRNO_MAP(V) 
10. #undef V 
11. };

UV_ERRNO_MAP宏展開后如下

?
1
2
3
4
1.  {UV_E2BIG, "E2BIG", "argument list too long"}, 
2.  {UV_EACCES, "EACCES", "permission denied"}, 
3.  {UV_EADDRINUSE, "EADDRINUSE", "address already in use"}, 
4.  ……

所以導出到JS層的結果如下

?
1
2
3
4
5
6
1.  { 
2.    // 鍵是一個數字,由Libuv定義,其實是封裝了操作系統的定義
3.    UV_ECONNREFUSED: ["ECONNREFUSED", "connection refused"],   
4.    UV_ECONNRESET: ["ECONNRESET", "connection reset by peer"]  
5.    ...  
6.  }

Node.js最后會組裝這些信息返回給調用方。這就是我們輸出的錯誤信息。那么為什么會是ECONNREFUSED呢?我們看一下操作系統對于該錯誤碼的邏輯。

?
1
2
3
4
5
6
7
8
9
10
1.  static void tcp_reset(struct sock *sk) 
2.  { 
3.      switch (sk->sk_state) { 
4.          case TCP_SYN_SENT: 
5.              sk->sk_err = ECONNREFUSED; 
6.              break
7.           // ...
8.      } 
9.   
10. }

當操作系統收到一個發給該socket的rst包的時候會執行tcp_reset,我們看到當socket處于發送syn包等待ack的時候,如果收到一個fin包,則會設置錯誤碼為ECONNREFUSED。我們輸出的正是這個錯誤碼。

總結

到此這篇關于nodejs的錯誤處理過程記錄的文章就介紹到這了,更多相關nodejs錯誤處理內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://zhuanlan.zhihu.com/p/364638398

延伸 · 閱讀

精彩推薦
  • node.jslinux服務器快速卸載安裝node環境(簡單上手)

    linux服務器快速卸載安裝node環境(簡單上手)

    這篇文章主要介紹了linux服務器快速卸載安裝node環境(簡單上手),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    mose-x8462022-01-22
  • node.jsNode.js ObjectWrap 的弱引用問題

    Node.js ObjectWrap 的弱引用問題

    最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。...

    編程雜技9852022-01-04
  • node.js在瀏覽器中,把 Vite 跑起來了!

    在瀏覽器中,把 Vite 跑起來了!

    大家好,我是 ssh,前幾天在推上沖浪的時候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運行起來了。這引起了我的興趣,如...

    前端從進階到入院9282022-01-11
  • node.jsnodejs中使用worker_threads來創建新的線程的方法

    nodejs中使用worker_threads來創建新的線程的方法

    這篇文章主要介紹了nodejs中使用worker_threads來創建新的線程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    flydean程序那些事8982022-01-06
  • node.jsrequire加載器實現原理的深入理解

    require加載器實現原理的深入理解

    這篇文章主要給大家介紹了關于require加載器實現原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    隱冬8462022-03-03
  • node.jsNode.js 中如何收集和解析命令行參數

    Node.js 中如何收集和解析命令行參數

    這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    descire8802021-12-28
  • node.js詳解node.js創建一個web服務器(Server)的詳細步驟

    詳解node.js創建一個web服務器(Server)的詳細步驟

    這篇文章主要介紹了詳解node.js創建一個web服務器(Server)的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    王佳斌8952021-12-31
  • node.jsk8s node節點重新加入master集群的實現

    k8s node節點重新加入master集群的實現

    這篇文章主要介紹了k8s node節點重新加入master集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    Scarborought13922022-01-22
主站蜘蛛池模板: 久久人人爽人人爽人人片av高清 | 欧美日韩1区2区3区 黄片毛片一级 | 欧美特黄三级成人 | 欧美一区二区三区四区夜夜大片 | 中文字幕精品一区久久久久 | 黄色av免费 | 久久精品一二三区白丝高潮 | 免费视频a | 青青草好吊色 | 精品国产乱码久久久久久丨区2区 | 国产成人高清成人av片在线看 | 成人短视频在线播放 | 在线看毛片的网站 | 一级片九九| 一级电影在线观看 | 羞羞色院91精品网站 | 草草视频免费 | 色污视频 | 一区二区三区国产好的精 | 久久精品视频网址 | 羞羞草视频 | 成人偷拍片视频在线观看 | 欧美成人性色区 | 一级免费黄色免费片 | 中文字幕亚洲一区二区三区 | 一级黄色国产视频 | 国产亚洲精品久久久久5区 综合激情网 | 欧美性生交zzzzzxxxxx | 精品一区二区三区电影 | 日本一区二区在线 | 成年人视频免费 | 中文字幕综合 | 亚洲第一页综合 | 性少妇chinesevideo | 国产午夜精品在线 | 九七在线视频 | 好骚综合在线 | 中文欧美日韩 | 亚洲视屏在线 | 国产资源在线观看视频 | 国产免费一区二区三区在线能观看 |