{"id":1138,"date":"2018-06-18T16:47:28","date_gmt":"2018-06-18T15:47:28","guid":{"rendered":"https:\/\/solidt.eu\/site\/?p=1138"},"modified":"2025-12-16T16:48:24","modified_gmt":"2025-12-16T15:48:24","slug":"callbags","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/callbags\/","title":{"rendered":"Callbags"},"content":{"rendered":"\n<p><a href=\"https:\/\/loreanvictor.github.io\/callbag-common\/what-are-callbags\">https:\/\/loreanvictor.github.io\/callbag-common\/what-are-callbags<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/callbag\/callbag\">https:\/\/github.com\/callbag\/callbag<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/staltz\/callbag-basics\">https:\/\/github.com\/staltz\/callbag-basics<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/staltz\/callbag-pseudo-rxjs\">https:\/\/github.com\/staltz\/callbag-pseudo-rxjs<\/a><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/from https:\/\/www.npmjs.com\/package\/callbag-catch-error\nconst catchError = fn => source => (start, sink) => {\n  if (start !== 0) return;\n  source(0, (type, data) => {\n    type === 2 &amp;&amp; typeof data !== 'undefined' ? fn(data) : sink(type, data);\n  });\n};\n\nfunction* range(from, to) {\n  let i = from;\n  while (i &lt;= to) {\n    yield i;\n    i++;\n  }\n}\n\nconst fromEvent = (node, name) => (start, sink) => {\n  if (start !== 0) return;\n  const handler = ev => sink(1, ev);\n  sink(0, t => {\n    if (t === 2) node.removeEventListener(name, handler);\n  });\n  node.addEventListener(name, handler);\n};\n\nconst fromIter = iter => (start, sink) => {\n    if (start !== 0) return;\n    const iterator =\n        typeof Symbol !== 'undefined' &amp;&amp; iter[Symbol.iterator] ?\n        iter[Symbol.iterator]() :\n        iter;\n    let inloop = false;\n    let got1 = false;\n    let res;\n\n    function loop() {\n        inloop = true;\n        while (got1) {\n            got1 = false;\n            res = iterator.next();\n            if (res.done) sink(2);\n            else sink(1, res.value);\n        }\n        inloop = false;\n    }\n    sink(0, t => {\n        if (t === 1) {\n            got1 = true;\n            if (!inloop &amp;&amp; !(res &amp;&amp; res.done)) loop();\n        }\n    });\n};\n\nconst interval = (period) => {\n    return (start, sink) => {\n        if (start !== 0) return;\n        let i = 0;\n        const id = setInterval(() => {\n            sink(1, i++);\n        }, period);\n        sink(0, t => {\n            if (t === 2) {\n                clearInterval(id);\n            }\n        });\n    };\n};\n\nconst forEach = (operation) => {\n    return (source) => {\n        let talkback;\n        source(0, (t, d) => {\n            if (t === 0) talkback = d;\n            if (t === 1) operation(d);\n            if (t === 1 || t === 0) talkback(1);\n        });\n    };\n};\n\nconst loop = (operation) => {\n    return (source) => {\n        let talkback;\n        source(0, (t, d) => {\n            if (t === 0) talkback = d;\n            if (t === 1) operation(d);\n        });\n    };\n};\n\nconst delay = (duration) => source => {\n    return (type, sink) => {\n        if (type !== 0) return\n        source(0, (t, d) => {\n            if (t !== 1) return sink(t, d)\n            let id = setTimeout(() => {\n                clearTimeout(id)\n                sink(1, d)\n            }, duration)\n        })\n    }\n};\n\nconst until = (fn) => {\n    return (source) => {\n        return (type, sink) => {\n            if (type !== 0) return;\n            let talkback;\n            source(0, (t, d) => {\n                if (t === 0)\n                {\n                    talkback = d;\n                    sink(0, (t2) => {\n                        if (t2 === 1) talkback(1);\n                    });\n                }\n                if (t === 1) {\n                    if (fn(d)) {\n                        talkback(2);\n                    } else {\n                        sink(1, d);\n                    }\n                }\n            });\n        }\n    }\n}\n\nfunction pipe(...cbs) {\n    let res = cbs[0];\n    for (let i = 1, n = cbs.length; i &lt; n; i++) {\n        let f = cbs[i];\n        res = f(res);\n    }\n    return res;\n};\n\n\/\/pipe(fromIter(range(10, 60)),  until((d) => d > 40), forEach(x => console.log(x)));\n\/\/pipe(interval(500), until((d) => d > 5), forEach(x => console.log(x)));\n\/\/pipe(interval(20), until((d) => d > 500), loop(x => console.log(x)));\n<\/pre>\n\n\n\n<p>Source: <a href=\"http:\/\/blog.krawaller.se\/posts\/explaining-callbags-via-typescript-definitions\/\">http:\/\/blog.krawaller.se\/posts\/explaining-callbags-via-typescript-definitions\/<\/a><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">export type START = 0;\nexport type DATA = 1;\nexport type END = 2;\n\nexport type Callbag = (type: START | DATA | END, payload?: any) => void;\nexport type Factory = (...args: Array&lt;any>) => Callbag;\nexport type Operator = (...args: Array&lt;any>) => (source: Callbag) => Callbag;\n\ntype SourceTalkback = \n  &amp; ((request: DATA) => void)\n  &amp; ((terminate: END) => void);\n\ntype SinkTalkback = \n  &amp; ((start: START, sourceTalkback: SourceTalkback) => void)\n  &amp; ((deliver: DATA, data: any) => void)\n  &amp; ((terminate: END, error?: any) => void);\n\ntype SourceInitiator = (type: START, payload: SinkTalkback) => void;\n\ntype SinkConnector = (source: SourceInitiator) => SourceInitiator | void;\n\ntype SourceFactory = (...args: Array&lt;any>) => SourceInitiator;\n\ntype Operator = (...args: Array&lt;any>) => SinkConnector;\n<\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"387\" height=\"153\" src=\"https:\/\/solidt.eu\/site\/wp-content\/uploads\/2019\/07\/afbeelding.png\" alt=\"\" class=\"wp-image-2446\" srcset=\"https:\/\/solidt.eu\/site\/wp-content\/uploads\/2019\/07\/afbeelding.png 387w, https:\/\/solidt.eu\/site\/wp-content\/uploads\/2019\/07\/afbeelding-300x119.png 300w\" sizes=\"auto, (max-width: 387px) 100vw, 387px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/blog.krawaller.se\/diagrams\/callbag-typedefs.svg\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"reaping-the-rewards\">Reaping the rewards<\/h3>\n\n\n\n<p>With these typings down we can use them as a very precise vocabulary for explaining the process of using callbags!<\/p>\n\n\n\n<p>Here&#8217;s the setup and handshake:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We call a\u00a0<code>SinkConnector<\/code>\u00a0passing in a\u00a0<code>SourceInitiator<\/code>:\u00a0<code>sinkConnector(sourceInitiator)<\/code><\/li>\n\n\n\n<li>The\u00a0<code>SourceInitiator<\/code>\u00a0is called with a\u00a0<code>SinkTalkback<\/code>:\u00a0<code>sourceInitiator(0,sinkTalkback)<\/code><\/li>\n\n\n\n<li>The\u00a0<code>SinkTalkback<\/code>\u00a0is called with a\u00a0<code>SourceTalkback<\/code>:\u00a0<code>sinkTalkback(0,sourceTalkback)<\/code><\/li>\n<\/ol>\n\n\n\n<p>And data passing:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The\u00a0<code>SourceTalkback<\/code>\u00a0is called with a request for data (if pullable):\u00a0<code>sourceTalkback(1)<\/code><\/li>\n\n\n\n<li>The\u00a0<code>SinkTalkback<\/code>\u00a0is called with data delivery:\u00a0<code>sinkTalkback(1,data)<\/code><\/li>\n<\/ol>\n\n\n\n<p>And termination:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The\u00a0<code>SourceTalkback<\/code>\u00a0can be called to terminate the relationship:\u00a0<code>sourceTalkback(2)<\/code><\/li>\n\n\n\n<li>The\u00a0<code>SinkTalkback<\/code>\u00a0can be called to terminate the relationship:\u00a0<code>sinkTalkback(2)<\/code><\/li>\n\n\n\n<li>The\u00a0<code>SinkTalkback<\/code>\u00a0can be called to terminate the relationship due to an error:\u00a0<code>sinkTalkback(2,error)<\/code><\/li>\n<\/ul>\n\n\n\n<p><a href=\"https:\/\/egghead.io\/articles\/comparing-callbags-to-rxjs-for-reactive-programming\">https:\/\/egghead.io\/articles\/comparing-callbags-to-rxjs-for-reactive-programming<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/staltz\/callbag-pseudo-rxjs\">https:\/\/github.com\/staltz\/callbag-pseudo-rxjs<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"679\" src=\"https:\/\/solidt.eu\/site\/wp-content\/uploads\/2021\/09\/afbeelding-1-1024x679.png\" alt=\"\" class=\"wp-image-5350\" srcset=\"https:\/\/solidt.eu\/site\/wp-content\/uploads\/2021\/09\/afbeelding-1-1024x679.png 1024w, https:\/\/solidt.eu\/site\/wp-content\/uploads\/2021\/09\/afbeelding-1-300x199.png 300w, https:\/\/solidt.eu\/site\/wp-content\/uploads\/2021\/09\/afbeelding-1-768x509.png 768w, https:\/\/solidt.eu\/site\/wp-content\/uploads\/2021\/09\/afbeelding-1.png 1105w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/loreanvictor.github.io\/callbag-common\/what-are-callbags https:\/\/github.com\/callbag\/callbag https:\/\/github.com\/staltz\/callbag-basics https:\/\/github.com\/staltz\/callbag-pseudo-rxjs Source: http:\/\/blog.krawaller.se\/posts\/explaining-callbags-via-typescript-definitions\/ Reaping the rewards With these typings down we can use them as a very precise vocabulary for explaining the process of using callbags! Here&#8217;s the setup and handshake: And data passing: And termination: https:\/\/egghead.io\/articles\/comparing-callbags-to-rxjs-for-reactive-programming https:\/\/github.com\/staltz\/callbag-pseudo-rxjs<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[5],"tags":[],"class_list":["post-1138","post","type-post","status-publish","format-standard","hentry","category-javascript"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/1138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=1138"}],"version-history":[{"count":14,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/1138\/revisions"}],"predecessor-version":[{"id":9996,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/1138\/revisions\/9996"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=1138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=1138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=1138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}