iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
自我挑戰組

從C到JS的同步非同步探索系列 第 19

[Day 19] Node http request

  • 分享至 

  • xImage
  •  

前言

今天來看看, node 怎麼進行一個 http request

正文

打開 http.js 這個 module

https://github.com/nodejs/node/blob/master/lib/http.js

查看呼叫 request 的方法

/**
 * Makes an HTTP request.
 * @param {string | URL} url
 * @param {HTTPRequestOptions} [options]
 * @param {Function} [cb]
 * @returns {ClientRequest}
 */
function request(url, options, cb) {
  return new ClientRequest(url, options, cb);
}

查看 ClientRequest 物件

// initiate connection
  if (this.agent) {
    this.agent.addRequest(this, optsWithoutSignal);
  } else {
		// 略
  }

跳過資料處理與設定, 直接看 this.agent.addRequest(this, optsWithoutSignal);

這裡的 agent 是 TCP 連線的管理者, 這裡先取 TCP 連線管理者存在, 可以直接使用的情況。

查看 addRequest

if (socket) {
    asyncResetHandle(socket);
    this.reuseSocket(socket, req);
    setRequestSocket(this, req, socket);
    ArrayPrototypePush(this.sockets[name], socket);
    this.totalSocketCount++;
 }

跳過取得 socket 的過程, 取得 socket 後, 調用 setRequestSocket 準備寄出資料。

function setRequestSocket(agent, req, socket) {
  req.onSocket(socket);
  const agentTimeout = agent.options.timeout || 0;
  if (req.timeout === undefined || req.timeout === agentTimeout) {
    return;
  }
  socket.setTimeout(req.timeout);
}

忽略後面處理逾時的部分, 查看 onSocket

ClientRequest.prototype.onSocket = function onSocket(socket, err) {
  // TODO(ronag): Between here and onSocketNT the socket
  // has no 'error' handler.
  process.nextTick(onSocketNT, this, socket, err);
};

發現其調用 node API 進入下一個階段(何為階段後面會提), 查看送到後面的回調函數 onSocketNT

function onSocketNT(req, socket, err) {
  if (req.destroyed || err) {
    req.destroyed = true;

    function _destroy(req, err) {
      if (!req.aborted && !err) {
        err = connResetException('socket hang up');
      }
      if (err) {
        req.emit('error', err);
      }
      req._closed = true;
      req.emit('close');
    }

    if (socket) {
      if (!err && req.agent && !socket.destroyed) {
        socket.emit('free');
      } else {
        finished(socket.destroy(err || req[kError]), (er) => {
          if (er?.code === 'ERR_STREAM_PREMATURE_CLOSE') {
            er = null;
          }
          _destroy(req, er || err);
        });
        return;
      }
    }

    _destroy(req, err || req[kError]);
  } else {
    tickOnSocket(req, socket);
    req._flush();
  }
}

跳過例外處理, 直接看 tickOnSocket(req, socket);

// 略
socket.on('error', socketErrorListener);
socket.on('data', socketOnData);
socket.on('end', socketOnEnd);
socket.on('close', socketCloseListener);
socket.on('drain', ondrain);
// 略

發現註冊了一堆 callback function

明天進度

初看 node 的非同步處理, 我們挑了 http request 作為開始, 挖到底層後發現, 在 JS 部分做完應做的設定後主要是註冊了一堆回調函數。

我們明天就來看看這些回調函數會被註冊到哪吧 !

明天見 !


上一篇
[Day 18] Node.js 的非同步小實驗
下一篇
[Day 20] Node 註冊事件 1
系列文
從C到JS的同步非同步探索30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言