国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

什么!?nodejs 實(shí)現(xiàn)的同步網(wǎng)絡(luò)請求?

Rindia / 2867人閱讀

摘要:以異步方式事件隊列為標(biāo)準(zhǔn),基本每一套與網(wǎng)絡(luò)相關(guān)的都會設(shè)計成異步的。在這種情況下,同步的網(wǎng)絡(luò)請求比異步的請求會更加合適,代碼更加清晰,邏輯更簡單,而且對代碼效率要求不高。如下,便是簡化后的同步請求,文本替換的代碼。

node.js 以異步方式、事件隊列為標(biāo)準(zhǔn),基本每一套與網(wǎng)絡(luò)、IO 相關(guān)的 API 都會設(shè)計成異步的。

如,一段很平常的請求代碼,用 node.js 只能用異步方式。

const https = require("https");

https.get("https://nodejs.org/api/https.html", res => res.pipe(process.stdout))

異步方式不會阻塞進(jìn)程,充分利用 CPU。

但是,對于一些一次性的腳本、批處理,我們希望使用同步的方式。因為以上情形,對于效率要求不是十分迫切,更多的是需要清晰的代碼結(jié)構(gòu),簡明的代碼邏輯。

本人在之前的 markdown-image-size 中,有這么個需求:

瀏覽器在未加載完圖片數(shù)據(jù)的時候,瀏覽器是不知道其大小的
所以,默認(rèn)大小都是 0,除非通過 style 設(shè)置了大小

之后的某個時候,圖片加載完成,瀏覽器得到圖片大小,文章就會有跳動的感覺,閱讀體驗不佳

解決該問題,將 markdown 文本中的 ![](src) 中的 src 匹配出來,如果是本地文件則讀文件,得到圖片大小;或者發(fā)送請求,得到圖片數(shù)據(jù)進(jìn)而得到圖片大小,最后進(jìn)行字符串 替換/插入,成為如下的 HTML 格式文本。

在這種情況下,同步的網(wǎng)絡(luò)請求比異步的請求會更加合適,代碼更加清晰,邏輯更簡單,而且對代碼效率要求不高。如下,便是簡化后的同步請求,文本替換的代碼。

content.replace(/![(.*)]((.*?[^]))/g, (matched, alt, src) => {
    // get image data from src synchronously
    const data = getData(src);
    const size = sizeOf(data);
    return ``
})

如果使用的是異步,則不能在第二個參數(shù)中直接 return 替換后的文本了,就需要更加復(fù)雜的代碼邏輯(如標(biāo)記文本的位置和長度,待請求結(jié)束后,進(jìn)行替換)。

那么具體應(yīng)該如何實(shí)現(xiàn) node.js 的同步請求呢?

谷歌 "sync request in nodejs"

搜索結(jié)果中出來一個 sync-request, npm install 后果然能夠同步網(wǎng)絡(luò)請求,這頓時勾起了我的興趣:在一個官方?jīng)]有提供同步請求 api 的情況下,該第三方包是怎么實(shí)現(xiàn)請求的同步的呢?

閱讀源碼之后才發(fā)現(xiàn)作者十分巧妙的將異步問題轉(zhuǎn)化成了同步問題,分析如下。

sync-request

在 readme 中,作者有這樣一段話:

How is this possible?

Internally, this uses a separate worker process that is run using childProcess.spawnSync.

The worker then makes the actual request using then-request so this has almost exactly the same API as that.

This can also be used in a web browser via browserify because xhr has built in support for synchronous execution. Note that this is not recommended as it will be blocking.

簡言之作者實(shí)際上發(fā)送請求是用的 then-request,對官方的異步 API 用 Promise 進(jìn)行封裝,所以其是異步請求方式。

異步轉(zhuǎn)化同步方式,主要是借助了 childProcess.spawnSync 方法,創(chuàng)建同步進(jìn)程

閱讀源碼之后,基本的流程如下:

首先需要 nc 指令的作用,以及標(biāo)準(zhǔn)輸入輸出如何傳遞字節(jié)數(shù)組。

man page 中對 nc 的介紹為:

nc -- arbitrary TCP and UDP connections and listens
usage: nc [hostname] [port[s]]

就是一個底層的系統(tǒng)調(diào)用,用于建立 TCP/UDP 連接或者監(jiān)聽某端口的,由于是系統(tǒng)調(diào)用,所以速度更快,效率更高。

標(biāo)準(zhǔn)輸入輸出如何傳遞字節(jié)數(shù)組,就需要將字節(jié)數(shù)組轉(zhuǎn)化成字符串,然后在處理之前轉(zhuǎn)化成字節(jié)數(shù)組,默認(rèn) nodejs 實(shí)現(xiàn)是將 Buffer 序列化為 {"type":"Buffer","data":[1,2,3,4,5]},分成2個字段表示,但是這樣是不能夠反序列化回來的。

則需要重寫 JSON 序列化的方法,主要是對 Buffer 的處理。

function stringify (o) {
    if(o && Buffer.isBuffer(o)) // hex, ascii 都是可以的
        return JSON.stringify(":base64:" + o.toString("base64"));
    if ("string" === typeof o) {
        // 避免將 buffer 誤認(rèn)為 string
        return JSON.stringify(/^:/.test(o) ? ":" + o : o)
    }
    // 其他維持原樣
}

function parse (o) {
    return JSON.parse(s, function (key, value) {
        if("string" === typeof value) {
          if(/^:base64:/.test(value))
            return new Buffer(value.substring(8), "hex")
          else // string
            return /^:/.test(value) ? value.substring(1) : value
        }
        return value
    })
}

理解了以上之后,再來具體看看代碼

find-port.js
得到一個空閑的端口返回,基本原理如下(僅為部分代碼)

module.exports = function () {
    return new Promise(function (resolve, reject) {
        var server = net.createServer();

        server.unref();
        server.on("error", reject);
        // port = 0, 綁定可用的端口
        server.listen(0, function () {
            var port = server.address().port;

            server.close(function () {
                resolve(port);
            });
        });
    });
};

legacy-work.js
使用標(biāo)準(zhǔn)輸入輸出作為參數(shù)的來源和返回的出口,處理網(wǎng)絡(luò)請求 (then-request)

const concat = require("concat-stream");
const request = require("then-request");
const JSON = require("./json-buffer");

function respond(data) {
  process.stdout.write(JSON.stringify(data), function() {
    process.exit(0);
  });
}

process.stdin.pipe(concat(function (stdin) {
  var req = JSON.parse(stdin.toString());
  request(req.method, req.url, req.options).done(function (response) {
    respond({success: true, response: response});
  }, function (err) {
    respond({success: false, error: { message: err.message }});
  });
}));

nc-server.js
啟動一個 TCP 服務(wù)端,為 nc 指令通信

const net = require("net");
const concat = require("concat-stream");
const request = require("then-request");
const JSON = require("./json-buffer");

const server = net.createServer({allowHalfOpen: true}, c => {
  function respond(data) {
    c.end(JSON.stringify(data));
  }

  c.pipe(concat(function (stdin) {
    try {
      const req = JSON.parse(stdin.toString());
      request(req.method, req.url, req.options).done(function (response) {
        respond({success: true, response: response});
      }, function (err) {
        respond({success: false, error: { message: err.message }});
      });
    } catch (ex) {
      respond({success: false, error: { message: ex.message }});
    }
  }));
});

server.listen(+process.argv[2]);

其中 { allowHalfOpen: true } 不可少,因為在執(zhí)行 spawnSync("nc", ["127.0.0.1", nPort], {input: request}) 時,input 是 JSON 序列話后的字符串,輸入后就到 EOF 了,相當(dāng)于在 Shell 中 Ctrl+D 控制鍵,nc 客戶端套接字就關(guān)閉了,只有允許半開套接字,客戶端才能收到服務(wù)器的數(shù)據(jù)。如下圖:對應(yīng)為客戶端的 FIN_WAIT_2 ~ TIME_WAIT 周期之間,服務(wù)器依舊可以發(fā)送數(shù)據(jù)。

以上,便是對部分源碼的解析

所以,最終的請求還是通過 then-request 來實(shí)現(xiàn)的,但是對于 then-request 并不支持 multipart/formdata,因此 sync-request 也是不支持的。 于是本人在 fork 之后,配合 form-data 提了 pr,希望作者能夠早日 merge 吧。

最后想說:原來還可以這樣實(shí)現(xiàn)同步!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/81572.html

相關(guān)文章

  • Nodejs高性能原理(上) --- 異步非阻塞事件驅(qū)動模型

    摘要:使用了一個事件驅(qū)動非阻塞式的模型,使其輕量又高效。的包管理器,是全球最大的開源庫生態(tài)系統(tǒng)。按照這個定義,之前所述的阻塞,非阻塞,多路復(fù)用信號驅(qū)動都屬于同步。 系列文章 Nodejs高性能原理(上) --- 異步非阻塞事件驅(qū)動模型Nodejs高性能原理(下) --- 事件循環(huán)詳解 前言 終于開始我nodejs的博客生涯了,先從基本的原理講起.以前寫過一篇瀏覽器執(zhí)行機(jī)制的文章,和nodej...

    yy736044583 評論0 收藏0
  • Node.js 入門你需要知道 10 個問題

    摘要:什么是在中什么時候需要是中的包管理器。允許我們?yōu)榘惭b各種模塊,這個包管理器為我們提供了安裝刪除等其它命令來管理模塊。 showImg(https://user-gold-cdn.xitu.io/2019/7/11/16bde5b2df52a924?w=4000&h=2667&f=jpeg&s=450648); 本文為您分享「Node.js 入門你需要知道的 10 個問題」這些問題可能也...

    szysky 評論0 收藏0
  • 前端面試題大集合:來自真實(shí)大廠532道面試題(只有題,沒有答案)

    答案自己谷歌或百度找。 一、來源背景 面試題是來自微博@牛客網(wǎng)發(fā)布的真實(shí)大廠前端面經(jīng)題目,我一直在收集題目長期一個一個的記錄下來的,可能會有重復(fù),但基本前端的面試大綱和需要掌握的知識都在其中了,面試題僅做學(xué)習(xí)參考,學(xué)習(xí)者閱后也要用心鉆研其中的原理,重要知識需要系統(tǒng)學(xué)習(xí)、透徹學(xué)習(xí),形成自己的知識鏈。 二、532道前端真實(shí)大廠面試題 express和koa的對比,兩者中間件的原理,koa捕獲異常多種情...

    Kerr1Gan 評論0 收藏0
  • 前端面試題大集合:來自真實(shí)大廠532道面試題(只有題,沒有答案)

    答案自己谷歌或百度找。 一、來源背景 面試題是來自微博@牛客網(wǎng)發(fā)布的真實(shí)大廠前端面經(jīng)題目,我一直在收集題目長期一個一個的記錄下來的,可能會有重復(fù),但基本前端的面試大綱和需要掌握的知識都在其中了,面試題僅做學(xué)習(xí)參考,學(xué)習(xí)者閱后也要用心鉆研其中的原理,重要知識需要系統(tǒng)學(xué)習(xí)、透徹學(xué)習(xí),形成自己的知識鏈。 二、532道前端真實(shí)大廠面試題 express和koa的對比,兩者中間件的原理,koa捕獲異常多種情...

    lushan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<