Javascript(ES6)可编辑流

Javascript(ES6)可编辑流,javascript,stream,iterator,ecmascript-6,Javascript,Stream,Iterator,Ecmascript 6,是否有一种模式可以使用ES6生成器使流变得可访问 请参阅下面的“MakeStreeamIterable” import {createReadStream} from 'fs' let fileName = 'largeFile.txt' let readStream = createReadStream(fileName, { encoding: 'utf8', bufferSize: 1024 }) let myIterableAsyncStream = MakeStreamIte

是否有一种模式可以使用ES6生成器使流变得可访问

请参阅下面的“MakeStreeamIterable”

import {createReadStream} from 'fs'

let fileName = 'largeFile.txt'
let readStream = createReadStream(fileName, {
  encoding: 'utf8',
  bufferSize: 1024
})
let myIterableAsyncStream = MakeStreamIterable(readStream)

for (let data of myIterableAsyncStream) {
  let str = data.toString('utf8')
  console.log(str)
}
我对co或bluebird的协同程序或与deasync的阻塞不感兴趣

gold是MakeStreamIterable,应该是一个有效函数

是否有一种模式可以使用ES6生成器使流变得可访问

不,这无法实现,因为发电机是同步的。他们必须知道自己在什么时候屈服。异步数据源的迭代目前只能通过使用某种基于回调的实现来实现。因此,如果您所指的是“一个有效函数,其结果可以为循环的的的的一个的一个循环的一个的一个的一个的结果”,那么就没有办法使它成为“一个有效函数”

流是异步的 流表示在可能无限的时间内异步接收的可能无限的数据量。如果我们看一下,我们可以更详细地定义一个流是什么使得它“可联合”:

如果对象知道如何一次访问一个集合中的项,而跟踪其在该序列中的当前位置,则该对象就是迭代器。在JavaScript中,迭代器是一个对象,提供了一个next()方法,该方法返回序列中的下一项。此方法返回具有两个属性的对象:
done
value

(重点是我自己的。)

让我们从这个定义中找出iterable的属性。对象必须

  • 知道如何从集合中一次访问一个项目
  • 能够在数据序列中跟踪其当前位置
  • 并提供一个方法,
    next
    ,该方法检索具有属性的对象,该属性保存序列中的next
    值,或通知迭代已完成
  • 流不符合上述任何条件,因为

  • 它无法控制何时接收数据,无法“展望未来”找到下一个值
  • 它无法知道何时或是否已接收到所有数据,只能知道流何时关闭
  • 并且它不实现,因此不公开一个
    for of
    可以使用的
    next
    方法
  • ______

    假装 实际上,我们不能迭代从流接收的数据(绝对不能为of
    使用
    ),但是我们可以通过使用承诺(耶!)并在闭包中抽象出流的事件处理程序来构建一个假装的接口

    // MakeStreamIterable.js
    export default function MakeStreamIterable (stream) {
      let collection = []
      let index = 0
      let callback
      let resolve, reject
    
      stream
        .on('error', err => reject && reject(err))
        .on('end', () => resolve && resolve(collection))
        .on('data', data => {
          collection.push(data)
    
          try {
            callback && callback(data, index++)
          } catch (err) {
            this.end()
            reject(err)
          }
        })
    
      function each (cb) {
        if(callback) {
          return promise
        }
    
        callback = (typeof cb === 'function') ? cb : null
    
        if (callback && !!collection) {
            collection.forEach(callback)
            index = collection.length
        }
    
        return promise
      }
    
      promise = new Promise((res, rej) => {
        resolve = res
        reject = rej
      })
    
      promise.each = each
    
      return promise
    }
    
    我们可以这样使用它:

    import {MakeStreamIterable} from './MakeStreamIterable'
    
    let myIterableAsyncStream = MakeStreamIterable(readStream)
    
    myIterableAsyncStream
      .each((data, i) => {
        let str = data.toString('utf8')
        console.log(i, str)
      })
      .then(() => console.log('completed'))
      .catch(err => console.log(err))
    
    有关此实现的注意事项:

    • 无需立即调用“iterable stream”上的每个
  • 调用
    每个
    时,调用之前接收到的所有值都会以
    forEach
    -style一个接一个地传递给回调。之后,所有后续数据将立即传递给回调
  • 该函数返回一个承诺,在流结束时解析完整的
    数据收集
    ,这意味着如果
    每个
    提供的迭代方法不令人满意,我们实际上根本不必调用
    每个
  • 我培养了称之为迭代器的错误语义,因此我是一个可怕的人。请向有关当局报告

    • 很快您就可以使用。在node 9.8中,您可以通过运行
      --harmony
      命令行选项来使用它

      async function* streamAsyncIterator(stream) {
        // Get a lock on the stream
        const reader = stream.getReader();
      
        try {
          while (true) {
            // Read from the stream
            const {done, value} = await reader.read();
            // Exit if we're done
            if (done) return;
            // Else yield the chunk
            yield value;
          }
        }
        finally {
          reader.releaseLock();
        }
      }
      
      async function example() {
        const response = await fetch(url);
      
        for await (const chunk of streamAsyncIterator(response.body)) {
          // …
        }
      }
      
      感谢杰克·阿奇博尔德的上述贡献。

      2020更新: 看起来流在未来将是“本机”可移植的—只需等待浏览器来实现它:

      等待的
      (流的常量块){
      ...
      }
      
      您如何定义它(什么是
      数据
      …)?一个字节接一个字节(看起来不是这样的)?数据来自readStream。在('data',data=>…)上,我无法找到解决方案。在我看来,这似乎是不可能的。我认为没有co之类的东西,你是不可能做到的。你为什么反对这一点?
      对于……的
      是同步的。不能在异步数据源上同步迭代。有一个关于异步迭代器的建议,但是它被放弃了。很好的抽象。像这样的东西应该是内置的。