Node.Js dizeden akışları nasıl oluşturulur?


Yanıtlar:


27

10.17 düğümünden, fromstream.Readable, herhangi bir yinelenebilir öğeden (dizi değişmez değerleri içeren) kolayca akış oluşturmak için bir yönteme sahiptir:

const { Readable } = require("stream")

const readable = Readable.from(["input string"])

readable.on("data", (chunk) => {
  console.log(chunk) // will be called once with `"input string"`
})

En az 10.17 ve 12.3 arasında bir dizenin kendisinin yinelenebilir olduğunu unutmayın, bu yüzden Readable.from("input string")işe yarayacaktır, ancak karakter başına bir olay yayar. Readable.from(["input string"])dizideki öğe başına bir olay gönderir (bu durumda bir öğe).

Ayrıca daha sonraki düğümlerde (muhtemelen 12.3, belgeler o zaman fonksiyonun değiştirildiğini söylediğinden), dizeyi bir diziye sarmak artık gerekli değildir.

https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options


Göre stream.Readable.from , ip ya da tampon olmaz Readable.from (string) ya da Readable.from (tampon) arama performansı artırmak için diğer akımlar semantik eşleşecek şekilde iterated.
abbr

Benim hatam. İşlev 10.7'de eklendi ve başlangıçta tarif ettiğim şekilde davrandı. O zamandan beri, dizelerin artık dizilere sarılmasına gerek yok (12.3'ten beri artık her karakteri ayrı ayrı yinelemiyor).
Fizker

186

As @substack beni düzeltilmiş #node , yeni akımları API Düğüm v10 bu kolaylaştırır:

const Readable = require('stream').Readable;
const s = new Readable();
s._read = () => {}; // redundant? see update below
s.push('your text here');
s.push(null);

… Daha sonra serbestçe borulayabilir veya istediğiniz tüketiciye aktarabilirsiniz.

Resumer tek astar kadar temiz değildir , ancak ekstra bağımlılığı önler.

( Güncelleme: v0.10.26 ile v9.2.1 arasında şimdiye kadar, siz ayarlamadıysanız pushdoğrudan REPL isteminden yapılan bir çağrı bir not implementedistisna dışında kilitlenir _read. Bir işlev veya komut dosyasının içinde çökmez . sinir, dahil noop.)


6
Gönderen docs (bağlantı) : "Tüm Okunabilir akışı uygulamaları bir sağlamalıdır _readyatan kaynaktan veri almak için yöntem."
Felix Rabe

2
@eye_mew Önce ('akış') gerekir
Jim Jones

8
Neden nullakışın tampon belleğine itiyorsun?
dopatraman

5
@dopatraman nullakışa tüm verileri okumayı bitirdiğini ve akışı kapattığını söyler
chrishiestand

2
Görünüşe göre bunu böyle yapmamalısın. Dokümanlardan alıntı : “ readable.push()Yöntemin yalnızca Okunabilir Uygulayıcılar tarafından ve yalnızca readable._read()yöntemin içinden çağrılması amaçlanmıştır .”
Axel Rauschmayer

127

Jo Liss'in resumer yanıtını kullanmayın. Çoğu durumda işe yarar, ama benim durumumda iyi bir 4 veya 5 saat hata bulma kaybettim. Bunu yapmak için üçüncü taraf modüllere gerek yoktur.

YENİ CEVAP :

var Readable = require('stream').Readable

var s = new Readable()
s.push('beep')    // the string you want
s.push(null)      // indicates end-of-file basically - the end of the stream

Bu tamamen uyumlu bir Okunabilir akış olmalıdır. Akışları doğru kullanma hakkında daha fazla bilgi için buraya bakın .

ESKİ YANIT : Sadece yerel PassThrough akışını kullanın:

var stream = require("stream")
var a = new stream.PassThrough()
a.write("your string")
a.end()

a.pipe(process.stdout) // piping will work as normal
/*stream.on('data', function(x) {
   // using the 'data' event works too
   console.log('data '+x)
})*/
/*setTimeout(function() {
   // you can even pipe after the scheduler has had time to do other things
   a.pipe(process.stdout) 
},100)*/

a.on('end', function() {
    console.log('ended') // the end event will be called properly
})

'Kapat' olayının yayınlanmadığını unutmayın (akış arayüzleri için gerekli değildir).


2
@Finn Herhangi bir argüman yoksa javascript'teki parenslere ihtiyacınız yoktur
BT

2018'de "var" kullanmayın! but const
stackdave

30

Sadece streammodülün yeni bir örneğini oluşturun ve ihtiyaçlarınıza göre özelleştirin:

var Stream = require('stream');
var stream = new Stream();

stream.pipe = function(dest) {
  dest.write('your string');
  return dest;
};

stream.pipe(process.stdout); // in this case the terminal, change to ya-csv

veya

var Stream = require('stream');
var stream = new Stream();

stream.on('data', function(data) {
  process.stdout.write(data); // change process.stdout to ya-csv
});

stream.emit('data', 'this is my string');

13
Bu kod akış kurallarını ihlal eder. pipe()en azından hedef akışı döndürmesi gerekiyor.
greim

2
Bu kodu kullanırsanız end olayı çağrılmaz. Bu, genel olarak kullanılabilecek bir akış oluşturmanın iyi bir yolu değildir.
BT

12

Edit: Garth'ın cevabı muhtemelen daha iyidir.

Eski yanıt metnim aşağıda korunmaktadır.


Bir akışa bir dize dönüştürmek için, bir durdurulmuş kullanabilirsiniz aracılığıyla stream:

through().pause().queue('your string').end()

Misal:

var through = require('through')

// Create a paused stream and buffer some data into it:
var stream = through().pause().queue('your string').end()

// Pass stream around:
callback(null, stream)

// Now that a consumer has attached, remember to resume the stream:
stream.resume()

Kullanım durumumda çalışmak için zeMirco'nun çözümünü alamadım, ancak resumeroldukça iyi çalıştı. Teşekkürler!
mpen

@Substack resumer öneri benim için çok iyi çalıştı. Teşekkürler!
Garth Kidd

2
Resumer harika, ancak "nextTick'te akışı otomatik olarak sürdürür", akışı bilinmeyen tüketicilere aktarabileceğinizi düşünüyorsanız sürprizler sağlayabilir! Meta veri bir db kaydetme başarılı olsaydı bir dosyaya bir içerik akışı piped bazı kod vardı. Bu gizlenen bir hataydı, db yazma derhal başarı döndürdüğünde başarılı oldu! Daha sonra bir zaman uyumsuz bloğun içinde olan şeyleri yeniden düzenledim ve patlama, akış asla okunamazdı. Ders: Akışınızı kimin kullanacağını bilmiyorsanız, through (). Pause (). Kuyruk ('string'). End () tekniğine sadık kalın.
Jolly Roger

1
Bu cevabın resumer kısmını kullandığım için kodumu hata ayıklamak için yaklaşık 5 saat geçirdim. Eğer istersen harika olurdu .. kaldır
BT

10

Bunun için bir modül var: https://www.npmjs.com/package/string-to-stream

var str = require('string-to-stream')
str('hi there').pipe(process.stdout) // => 'hi there' 

1
Bu "bunun için bir uygulama var" üzerine bir kelime oyunu mu? ;)
masterxilo


Bilginize Google Drive'a JSON yazmak için bu kütüphaneyi kullanmaya çalıştım ama benim için işe yaramaz. Bu konuda bir makale yazdı: medium.com/@dupski/… . Ayrıca cevap olarak eklendi
Russell Briggs

6

kahve senaryosunda:

class StringStream extends Readable
  constructor: (@str) ->
    super()

  _read: (size) ->
    @push @str
    @push null

kullanın:

new StringStream('text here').pipe(stream1).pipe(stream2)

6

Başka bir çözüm, okuma işlevini Readable (cf doc akışı okunabilir seçenekleri ) yapıcısına iletmektir

var s = new Readable({read(size) {
    this.push("your string here")
    this.push(null)
  }});

örnek sonra s.pipe kullandıktan sonra yapabilirsiniz


sonunda geri dönüşün amacı nedir?
Kirill Reznikov

"her zaman bir şey (ya da hiçbir şey) döndürmeyin", bu dokümantasyondan muaftır.
Philippe T.

JS'de, bir işlevin dönüşü yoksa, bu, boş dönüşünüze eşdeğerdir. Lütfen bulduğunuz yere bir link verebilir misiniz?
Kirill Reznikov

haklısın. En iyi uygulama için daha fazlasını söyledim. Hiçbir şey geri dönmek istemiyorum, bu bir hata değil. Bu yüzden çizgiyi kaldırıyorum.
Philippe T.

5

Bunu her altı ayda bir yeniden öğrenmek zorunda kaldım, bu yüzden uygulama ayrıntılarını özetlemek için bir npm modülü yayınladım:

https://www.npmjs.com/package/streamify-string

Bu modülün çekirdeğidir:

const Readable = require('stream').Readable;
const util     = require('util');

function Streamify(str, options) {

  if (! (this instanceof Streamify)) {
    return new Streamify(str, options);
  }

  Readable.call(this, options);
  this.str = str;
}

util.inherits(Streamify, Readable);

Streamify.prototype._read = function (size) {

  var chunk = this.str.slice(0, size);

  if (chunk) {
    this.str = this.str.slice(size);
    this.push(chunk);
  }

  else {
    this.push(null);
  }

};

module.exports = Streamify;

strolduğu stringinvokation üzerine yapıcısına kabul edilmelidir, ve veriler gibi akım tarafından üretilen edilecektir. belgelereoptions göre bir akışa geçirilebilecek tipik seçeneklerdir .

Travis CI'ye göre, düğümün çoğu sürümüyle uyumlu olmalıdır.


2
Bu başlangıçta gönderdiğim zaman, ben kaşlarını çattı söylendi ilgili kodu dahil etmedi.
Chris Allen Lane

2

HerScript'te düzenli bir çözüm var:

import { Readable } from 'stream'

class ReadableString extends Readable {
    private sent = false

    constructor(
        private str: string
    ) {
        super();
    }

    _read() {
        if (!this.sent) {
            this.push(Buffer.from(this.str));
            this.sent = true
        }
        else {
            this.push(null)
        }
    }
}

const stringStream = new ReadableString('string to be streamed...')

1

JavaScript ördek türünde olduğundan, okunabilir bir akışın API'sını kopyalarsanız iyi çalışır. Aslında, muhtemelen bu yöntemlerin çoğunu uygulayamaz veya sadece saplama olarak bırakamazsınız; uygulamanız gereken tek şey kütüphanenin kullandığı şeydir. Olaylarla ilgilenmek için Düğüm'ün önceden oluşturulmuş EventEmittersınıfını da kullanabilirsiniz, böylece uygulamanız gerekmezaddListener kendinizi ve böyle bir kendiniz .

CoffeeScript'te nasıl uygulayabileceğiniz aşağıda açıklanmıştır:

class StringStream extends require('events').EventEmitter
  constructor: (@string) -> super()

  readable: true
  writable: false

  setEncoding: -> throw 'not implemented'
  pause: ->    # nothing to do
  resume: ->   # nothing to do
  destroy: ->  # nothing to do
  pipe: -> throw 'not implemented'

  send: ->
    @emit 'data', @string
    @emit 'end'

Sonra şöyle kullanabilirsiniz:

stream = new StringStream someString
doSomethingWith stream
stream.send()

Anladım: TypeError: string is not a function at String.CALL_NON_FUNCTION (native) ne zaman kullandığım zamannew StringStream(str).send()
pathikrit

JavaScript'in ördek yazmayı kullanması, tekerleği yeniden keşfetmeniz gerektiği anlamına gelmez. Düğüm zaten akışlar için bir uygulama sağlıyor. Sadece stream.Readable@Garth Kidd'in önerdiği yeni bir örneği oluşturun .
Sukima

4
@Sukima: Bu cevabı yazdığımda stream.Readable yoktu .
icktoofay
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.