问题
I am new super new to Promises and Node and am curious about using promises with streams. Can I promisify a stream? Using Bluebirdjs and the Twit module I have the following:
var Twit = require('twit')
var Promise = require("bluebird");
var T = new Twit({
consumer_key: process.env.CONSUMER_KEY,
consumer_secret: process.env.CONSUMER_SECRET,
access_token: process.env.ACCESS_TOKEN,
access_token_secret: process.env.ACCESS_TOKEN_SECRET
})
Promise.promisifyAll(Twit);
Promise.promisifyAll(T);
var sanFrancisco = [ '-122.75', '36.8', '-121.75', '37.8' ]
T.streamAsync('statuses/filter', { locations: sanFrancisco })
.then(function(connection){
connection.onAsync('tweet')
.then(function (tweet) {
console.log(tweet)
})
});
Running this code does not log a tweet and no error is thrown. Nothing happens the connection seems to be made but none of the .then promises work.
The original snippet, before trying to implement promises found in the twit docs
var sanFrancisco = [ '-122.75', '36.8', '-121.75', '37.8' ]
var stream = T.stream('statuses/filter', { locations: sanFrancisco })
stream.on('tweet', function (tweet) {
console.log(tweet)
})
回答1:
I'm sorry to say that won't work, because of a fundamental difference between a promise and a stream. You say you're new to both, so let me give you a short introduction to both.
Promises can be seen as placeholders for some single value that might not have arrived yet. For instance, some hypothetical function getTweet()
could work like this:
getTweet()
.then(function (tweet) {
//Do something with your tweet!
console.log(tweet);
});
But this would get you just a single tweet! To get another one, you'd have to call getTweet()
again, with a new .then()
behind that. In fact, when working with promises you have the guarantee that a .then()
calls its containing function only a single time!
Streams are continuous flows of data. You don't have to manually ask for a tweet, and then another one, and then another one. You open the tap, and then it just keeps coming until either it's finished or you tell it to stop.
So, in summary, you can't promisify a stream, because promises are for single values and streams for continuous flows of data.
I assume you asked the question because you like the promise interface and would like to use something similar for streams? Depending on what you're trying to achieve, there are different libraries that can make working with streams nicer. EventStream is one example. Let me know what you plan and I might be able to give you an example.
回答2:
I ended up using RxJS implementing observables with streams.
var sanFrancisco = [ '-122.75', '36.8', '-121.75', '37.8' ]
var stream = T.stream('statuses/filter', { locations: sanFrancisco });
var source = Rx.Node.fromEvent(stream, 'tweet');
var observer = Rx.Observer.create(
function (tweet) {
// THIS IS WHERE EACH TWEET SHOULD COME FROM THE STREAM
console.log(tweet);
},
function (err) {
console.log('Error getting tweets: ' + err);
},
function () {
console.log('Completed');
}
);
source.subscribe(observer);
I ended up having to use RX.Observable.fromEvent instead of Rx.Node.fromStream because, the Twit module must handle the actual stream behind the scenes but exposing it through and EventEmitter, they probably shouldn't have named it T.stream.
回答3:
Can I promisify a stream?
No. While a stream continuously emits events, a promise resolves only once. They have completely different semantics (even if both use asynchronous callbacks).
You can make a promise for a stream that ends, see the EventEmitterPromisifier example in BlueBirds documentation - but that's not what your twitter stream example does.
Running this code does not log a tweet and no error is thrown.
Because T.stream()
is a synchronous factory function that returns a stream object. You don't need - you cannot - use streamAsync
, as it will never invoke the implicitly passed callback.
来源:https://stackoverflow.com/questions/29013899/promises-and-streams-using-bluebird-js-and-twitter-stream