Javascript 预示溪流

Javascript 预示溪流,javascript,node.js,promise,eventemitter,Javascript,Node.js,Promise,Eventemitter,我试图向你保证,但这似乎比我想象的要难。以下是我的尝试: 'use strict' const Promise = require('bluebird') const Twitter = require('twitter') const TwitterStream = module.exports = function TwitterStream (config) { // init Twitter Streaming API for OAuth this.stream = new

我试图向你保证,但这似乎比我想象的要难。以下是我的尝试:

'use strict'

const Promise = require('bluebird')
const Twitter = require('twitter')

const TwitterStream = module.exports = function TwitterStream (config) {
  // init Twitter Streaming API for OAuth
  this.stream = new Twitter({
    consumer_key: config.get('/twitter/consumerKey'),
    consumer_secret: config.get('/twitter/consumerSecret'),
    access_token_key: config.get('/twitter/accessTokenKey'),
    access_token_secret: config.get('/twitter/accessTokenSecret')
  })
  .stream('statuses/filter', {
    track: config.get('/twitter/track')
  })
}

TwitterStream.prototype.receive = function () {
  return new Promise((resolve, reject) => {
    this.stream.on('data', resolve).on('error', reject)
  })
}

TwitterStream.prototype.destroy = function () {
  this.stream.destroy()
}
主要问题是当我创建对象时

const stream = new TwitterStream(config)

stream.receive().then((data) => console.log(data))
当我执行时,只读取一个对象。没有其他数据流

  TwitterStream.prototype.receive = function () {
     return new Promise((resolve, reject) => {
       this.stream
         .on('data', (data) => resolve(data)
         .on('error', (error) => reject(error))
       })
    }

您需要在
stream.on
函数的回调中返回承诺。现在,调用
receive
方法时,它只返回一个承诺,一旦解决,它将返回值或错误。

通过使用Rx扩展,它非常简单:

TwitterStream.prototype.receive = function () {
    return Rx.Observable.create((observer) => {
        this.stream
            .on('data', (data) => observer.onNext(data))
            .on('error', (err) => observer.onError(err));
    });
}
然后

const stream = new TwitterStream(config)

stream.receive().subscribe((data) => console.log(data));

下面是一段未经测试且很可能仍然存在错误的代码,以说明如何通过承诺实现这一点:

function defer() {
  var resolve, reject;
  var promise = new Promise(function() {
    resolve = arguments[0];
    reject = arguments[1];
  });
  return {
    resolve: resolve,
    reject: reject,
    promise: promise
  };
}


TwitterStream.prototype.receive = function() {

  this.stream
    .on('data', data => {
      this.dataCache = this.dataCache || [];
      this.dataCache.push(data);
      this.tryToSendData()
    })
    .on('end', () => {
      this.finished = true;
      this.tryToSendData()
    })
    .on('error', err => {
      this.lastError = err;
      // error handling still missing
    })

  return this;
}

TwitterStream.prototype.tryToSendData = function() {
  if (this.defered) {
    let defered = this.defered;
    this.defered = null;

    // if data is available or finished then pass the first element of buffer (or undefined)
    defered.resolve(this.dataCache.shift())
  }
}

TwitterStream.prototype.getNextData = function() {
  if (this.dataCache.length > 0 || this.finished) {
    // if data is available or finished then pass the first element of buffer (or undefined)
    return Promise.resolve(this.dataCache.shift());
  } else {
    // otherwise we need a defered object
    this.defered = defer();
  }
}
然后,用法可能如下所示:

stream.receive().getNextData()
  .then(function processData(data) {
    if (data) {
      console.dir(data);

      // if data is available then continue requestin the data
      return stream.getNextData().then(processData);
    }
  })

这是一个罕见的情况,你可以使用延迟。

我想你可能想看看我的,已经承诺的数据流

对于您的Twitter示例,此代码应该运行良好:

const stream = new Twitter({
    consumer_key: config.get('/twitter/consumerKey'),
    consumer_secret: config.get('/twitter/consumerSecret'),
    access_token_key: config.get('/twitter/accessTokenKey'),
    access_token_secret: config.get('/twitter/accessTokenSecret')
})
.stream('statuses/filter', {
   track: config.get('/twitter/track')
})
.pipe(new scramjet.DataStream)
然后执行您喜欢的任何转换。。。例如,以某种方式映射流,并在完成后将流累积到一个数组中

stream.map(
    function (a) { return modifyTheTweetSomehow(a); } // a Promise can be returned here
).accumulate(
    function(a, i) { a.push(i); },
    []
) // this returns a Promise that will be resolved on stream end.

我希望你喜欢

我不知道TwitterStreamAPI。此流是否无限期打开,只要有新数据(tweet)可用,就会发出
数据
事件。只有当连接中断时才会调用
end
?@t.niese是的,您不能直接将承诺映射到此类流。我将尝试创建一个示例来解决这个问题。您不能对流使用承诺:它们只产生一个值。使用Rx。可观察instead@olivarra1好的,谢谢,正如我预料的那样,那是不可能的,你是说?(编辑了问题)我已经尝试过了,但它不起作用。是的,因为函数在调用时将返回一个承诺。如果没有多次调用该流,则不会多次读取该流。注册事件处理程序将是更好的方法。我的答案本身是错误的,因为我没有正确理解这个问题。我的不好。虽然它看起来是多余的(因为在订阅时您仍然必须传入回调),但它与使用承诺时具有相同的好处:您可以应用map、compose等操作,这非常有用。