View observable-stream-3.js
// A non-streaming way to return Observable<User> from a URL
function fetchObservableOf(url) {
return new Observable(obs => {
fetch(url).then(data => {
data.users.forEach(user => obs.next(user));
obs.complete()
},
err => obs.error(err)
})
}
View observable-stream-2.js
function fetchObservableOf(url) {
return new Observable(obs => {
const stream = oboeGet(url)
stream.node("![*]", user => obs.next(user))
stream.done(obs.complete)
stream.fail(obs.error)
})
}
View observable-stream-1.js
fetchObservableOf('/users/').subscribe(
user => addToList(user), // next
e => showModal(e), // error
() => hideSpinner() // complete
)
View observable-streaming.md

I like to ask of technical people:

In a situation like the following, must you retry the request and lose the data you'd already seen? Scenario: You make an AJAX request like /users, and the server returns all 100 of those users to you like [{},{},..., but the server dies before sending the final ]

I've heard many interesting answers. Leave yours in the comments! And generally they are "yes, that's the way it works" But I think the question is a distraction from the real issue: I think we used the wrong tool for the job. We sent the request over a document-oriented protocol (HTTP) instead of an incremental frame-oriented protocol and so we get document-oriented semantics (all-or-nothing) rather than list-oriented semantics (item, item, item..). Clear as crystal, right?

But as always on the internet, there are counter-arguments. Some will say - HTTP is just how we transfer stuff. Or I hear that WebSockets- a better fit for this problem of incremental delivery- are too hard to impl

View fs-write.js
fs.appendFileSync(
"scratch/actors.yml", // file path
" - Scarlett Johansson", // text
"utf8" // encoding
)
View antares-1.11.js.diff
+const { bufferCount, map } = require("rxjs/operators")
const { Agent, after } = require("antares-protocol")
const agent = new Agent()
agent.addRenderer(fileRenderer, {
- concurrency: "serial"
+ concurrency: "serial",
+ xform: actionStream => actionStream.pipe(
+ bufferCount(25),
+ map(consolidator)
View antares-1.10.js.diff
+const consolidator = batch => {
+ let combinedNames = ""
+ for(let item of batch) {
+ const { action } = item
+ combinedNames += `${action.payload.text}\n - `
+ }
+ combinedNames = combinedNames.replace(/\s-\s$/, "")
+
+ return {
+ action: writeLine(combinedNames)
View antares-1.9.js.diff
-const actions = [
- writeLine("Jake Weary"),
- writeLine("ScarJo"),
- writeLine("Chris Hemsworth"),
- writeLine("Mark Ruffalo")
-]
-
+ // Cycle these 4 names 100 times
+const names = ["Jake Weary", "ScarJo", "Chris Hemsworth", "Mark Ruffalo"]
+
View antares-1.8.js.diff
-agent.addRenderer(fileRenderer)
+agent.addRenderer(fileRenderer, {
+ concurrency: "serial"
+})
agent.addFilter(logger)
View antares-1.7.js.diff
agent.addRenderer(fileRenderer)
-agent.addRenderer(logger)
+agent.addFilter(logger)