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

資訊專欄INFORMATION COLUMN

在 Node.js 中用 pipe 處理數(shù)組的實現(xiàn)

mikyou / 1943人閱讀

摘要:總結(jié)雖然我沒有像老師一樣進(jìn)行性能測試,但是猜測也知道的方式在數(shù)量比較小的時候肯定要弱于正常方式,的好處在于數(shù)據(jù)量比較大的時候,可以使用比較小的內(nèi)存,盡快的處理數(shù)組中前置的數(shù)據(jù)。

TLDR;
這篇文章的風(fēng)格是在致敬 Jim 老師;致敬,致敬,懂嗎,不是抄襲,程序員的事怎么能叫抄襲。
當(dāng)然我對 Node.js 的 stream 也是現(xiàn)學(xué)現(xiàn)賣,有使用不當(dāng)?shù)牡胤剑凑堉赋觥?br>原文鏈接 歡迎 star。

寫這篇文章的初衷是年前看 SICP 的時候,第二章介紹構(gòu)造數(shù)據(jù)抽象的時候有提到 Lisp 對序列的處理采用類似『信號流』的方式。所以很自然的就想到了 Node.js 中的 pipe 方式,于是就一直想用 pipe 的方式嘗試一下。

同 Jim 老師的這篇 文章 中描述的一樣, 我也是懶癌發(fā)作,從年尾拖到今年年初,然后在年初又看到了 Jim 老師 的博客,深受啟發(fā),終于下定決心要開始碼了...... 然后,嗯,又拖到昨天。促使我下定決心要寫的主要原因是昨天部門的年會!反正年會跟我這種死肥宅也沒多大關(guān)系,在大家 happy 的時候構(gòu)思了下代碼實現(xiàn),回家用了一晚上的時候補(bǔ)上了代碼。

Jim 老師在他的文章里面也說了,JS 的那些數(shù)組操作 (map/ reduce/filter) 啥的,每次調(diào)用的時候都會進(jìn)行一次完整的遍歷。試想一下如果有一個第一個數(shù)是1,長度是 1億 的遞增為 1 的數(shù)組,需要把所有的數(shù)組都乘 3,再排除其中的奇數(shù),如果用 (map/filter) 的方法,只要也需要循環(huán) 一億五千萬次;那么如果有其他辦法能只循環(huán)一億次,是不是節(jié)省了大量的內(nèi)存資源和循環(huán)消耗的時間。

廢話不多說,直接上代碼吧。

pipe

在編寫代碼時,我們應(yīng)該有一些方法將程序像連接水管一樣連接起來 -- 當(dāng)我們需要獲取一些數(shù)據(jù)時,可以去通過"擰"其他的部分來達(dá)到目的。這也應(yīng)該是IO應(yīng)有的方式。 -- Doug McIlroy. October 11, 1964

關(guān)于 node 的 stream 可以看看這篇 文章。

下面是代碼部分,整個代碼我是在邊學(xué) pipe 邊用一晚上的時間倉促寫就的,懶癌發(fā)作,也不想再重構(gòu)了,各位相公講究看吧,求別噴代碼。

入口
const stream = require("stream")

const last = Symbol()

// 在 selfArray 中接收一個真正的數(shù)組
// 返回一個可讀流
// 如果再做的精細(xì)點,可以做成可讀可寫流,這樣就能通過控制流的大小,來控制內(nèi)存的大小,別幾億條數(shù)據(jù)直接撐爆內(nèi)存了
// 不過對后面 reduce 的處理就比較麻煩
function selfArray(a) {
  const rs = new stream.Readable({
    objectMode: true
  })

  a.forEach((v, index) => {
    rs.push(v)
  })
  rs.push(last)
  rs.push(null)
  return rs
}

上面的 selfArray 在流的最后面 push 了一個 Symbol 對象來標(biāo)志整個流的輸入結(jié)束,留待為之后 reduce 的使用。

Map/Filter/Reduce 的實現(xiàn)
function forEach(callback) {
  const ws = new stream.Writable({
    objectMode: true
  })
  let index = 0

  ws._write = function (chunk, enc, next) {
    if (chunk !== last) {
      callback(chunk, index++)
      next()
    }
  }

  return ws
}

function filter(callback) {
  const trans = new stream.Transform({
    readableObjectMode: true,
    writableObjectMode: true
  })

  let index = 0

  trans._transform = function (chunk, enc, next) {
    if (chunk === last) {
      next(null, last)
    } else {
      let condition = callback(chunk, index++)
      if (condition) {
        this.push(chunk)
      }
      next()
    }
  }
  return trans
}

function map(callback) {
  const trans = new stream.Transform({
    readableObjectMode: true,
    writableObjectMode: true
  })
  let index = 0
  trans._transform = function (chunk, enc, next) {
    if (chunk === last) {
      next(null, last)
    } else {
      next(null, callback(chunk, index++))
    }
  }
  return trans
}

function reduce(callback, initial) {
  const trans = new stream.Transform({
    readableObjectMode: true,
    writableObjectMode: true
  })

  let index = 0,
    current = initial,
    prev = initial


  trans._transform = function (chunk, enc, next) {

    if (chunk === last) {
      if (index > 1) {
        prev = callback(prev, current, index - 1)
      }
      this.push(prev)
      this.push(last)
      return next(null, last)
    }

    if (initial === void 0 && index === 0) {
      prev = chunk
    }

    if (index > 0) {
      prev = callback(prev, current, index - 1)
    }

    current = chunk
    index++
    next()
  }

  return trans
}

上面的代碼在 reduce 的實現(xiàn)稍微麻煩了一些,reduce 對沒有初始值,原始數(shù)組為空的條件下有各種不同的處理情況,翻看了下 MDN 的解釋又自己實現(xiàn)了下。

使用
selfArray([9, 2, 6, 3, 5, 6, 7, 1, 4, 4])
  .pipe(map(v => v * 3))
  .pipe(filter(v => v % 2))
  .pipe(reduce((p, c) => p + c, 0))
  .pipe(forEach(v => {
    console.log("pipe 計算最后的結(jié)果是:", v)
  }))

為了好看我故意把各種括號都刪掉了。嗯,看起來還挺完美,我們來測試下

selfArray([9, 2, 6, 3, 5, 6, 7, 1, 4, 4])
  .pipe(map(v => {
    console.log("map:", v)
    return v * 3
  }))
  .pipe(filter(v => {
    console.log("filter:", v)
    return v % 2
  }))
  .pipe(reduce((p, c) => {
    console.log("reduce:", p, c)
    return p + c
  }, 0))
  .pipe(forEach(v => {
    console.log("pipe 計算最后的結(jié)果是:", v)
  }))
  
  
加上 log 之后可以看到結(jié)算結(jié)果是:
  
map: 9
filter: 27
map: 2
filter: 6
map: 6
filter: 18
map: 3
filter: 9
reduce: 0 27
map: 5
filter: 15
reduce: 27 9
map: 6
filter: 18
map: 7
filter: 21
reduce: 36 15
map: 1
filter: 3
reduce: 51 21
map: 4
filter: 12
map: 4
filter: 12
reduce: 72 3
pipe 計算最后的結(jié)果是: 75

從上面的 log 可以看到, 第一個數(shù) 9 先執(zhí)行了 map,然后在 3 之后就直接進(jìn)入了 filter,此時第 2 個數(shù) 2 也開始被 map 處理,然后被 filter 處理,但是由于 3 之后是偶數(shù)不會被 reduce 接收, reduce 會一直等到第二個奇數(shù),也就是 3 進(jìn)入之后才會被處理... 嗯,直到最終的計算結(jié)果是 75, 被 forEach 消耗。

總結(jié)

雖然我沒有像 Jim 老師一樣進(jìn)行性能測試,但是猜測也知道 pipe 的方式在數(shù)量比較小的時候肯定要弱于正常方式,pipe 的好處在于數(shù)據(jù)量比較大的時候,可以使用比較小的內(nèi)存,盡快的處理數(shù)組中前置的數(shù)據(jù)。

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

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

相關(guān)文章

  • Node.js 中用子進(jìn)程操作標(biāo)準(zhǔn)輸入/輸出

    摘要:在行中,我們將子進(jìn)程的連接到當(dāng)前進(jìn)程的。等待子進(jìn)程通過退出函數(shù)如下所示。子進(jìn)程的實現(xiàn)以下代碼用異步寫入以命令運行的子進(jìn)程的我們?yōu)槊钌梢粋€名為的獨立進(jìn)程。而是子進(jìn)程完成。沒有這個,將會在調(diào)用之前被輸出。 翻譯:瘋狂的技術(shù)宅原文:http://2ality.com/2018/05/chi... 本文首發(fā)微信公眾號:jingchengyideng歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)...

    leeon 評論0 收藏0
  • 我他喵到底要怎樣才能生產(chǎn)環(huán)境中用上 ES6 模塊化?

    摘要:因此,你還是需要各種各樣雜七雜八的工具來轉(zhuǎn)換你的代碼噢,我可去你媽的吧,這些東西都是干嘛的我就是想用個模塊化,我到底該用啥子本文正旨在列出幾種可用的在生產(chǎn)環(huán)境中放心使用模塊化的方法,希望能幫到諸位后來者這方面的中文資源實在是忒少了。 原文發(fā)表在我的博客上。最近搗鼓了一下 ES6 的模塊化,分享一些經(jīng)驗 :) Python3 已經(jīng)發(fā)布了九年了,Python 社區(qū)卻還在用 Python 2...

    KaltZK 評論0 收藏0
  • 認(rèn)識 Node .js

    摘要:服務(wù)器每收到一條請求,都會用新的和對象觸發(fā)請求回調(diào)函數(shù)。在調(diào)用完請求回調(diào)函數(shù)之后,就要由你負(fù)責(zé)用方法結(jié)束響應(yīng)。 前言 本文將介紹Node.js的一些基本概念,包含它的歷史,特性和簡單的使用等。如果你有過服務(wù)端的編程經(jīng)驗,那么你將能很快熟悉它。 Node.js是什么 showImg(https://segmentfault.com/img/bVbc24J?w=619&h=35); 這是N...

    I_Am 評論0 收藏0
  • [譯]關(guān)于Node.js streams你需要知道一切

    摘要:當(dāng)一個客戶端的響應(yīng)對象是一個可讀流,那么在服務(wù)器端這就是一個可寫流。的模塊給我們提供了一個可以操作任何文件的可讀流通過方法創(chuàng)建。創(chuàng)建一個可讀流創(chuàng)建可讀流,我們需要類創(chuàng)建一個可讀流非常簡單。可以通過修改可讀流配置里面的方法實現(xiàn)。 Node.js的stream模塊是有名的應(yīng)用困難,更別說理解了。那現(xiàn)在可以告訴你,這些都不是問題了。 多年來,開發(fā)人員在那里創(chuàng)建了大量的軟件包,其唯一目的就是使...

    bang590 評論0 收藏0
  • gulp詳細(xì)基礎(chǔ)教程

    摘要:核心概念流流,簡單來說就是建立在面向?qū)ο蠡A(chǔ)上的一種抽象的處理數(shù)據(jù)的工具。類型,設(shè)置輸出路徑以某個路徑的某個組成部分為基礎(chǔ)向后拼接。 一、gulp簡介 1.gulp是什么? gulp是前端開發(fā)過程中一種基于流的代碼構(gòu)建工具,是自動化項目的構(gòu)建利器;它不僅能對網(wǎng)站資源進(jìn)行優(yōu)化,而且在開發(fā)過程中很多重復(fù)的任務(wù)能夠使用正確的工具自動完成;使用它,不僅可以很愉快的編寫代碼,而且大大提高我們的工...

    xuhong 評論0 收藏0

發(fā)表評論

0條評論

mikyou

|高級講師

TA的文章

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