[Functional Programming] Use the Callback and Closure Pattern to Build Advanced Async Behaviors [Full code]

复制代码
import { curry, compose, toUpper, pipe } from 'ramda';

// #region listeners
const _log = (value) => console.log(value);
// #endregion

// #region broadcasters
const done = Symbol('done');
const addListener = curry((element, eventType, listener) => {
  return element.addEventListener(evenType, listener);
});
const createInterval = curry((time, listener) => {
  let i = 0;
  const id = setInterval(() => {
    listener(i++);
  }, time);
  return () => {
    clearInterval(id);
  };
});
const createForOf = curry((iterator, listener) => {
  const id = setTimeout(() => {
    for (let item of iterator) {
      listener(item);
    }
    listener(done);
  }, 0);
  return () => {
    clearTimeout(id);
  };
});
const createZipOf = curry((broadcaster1, broadcaster2, listener) => {
  let cancelBoth;
  let buffer1 = [];
  const cancel1 = broadcaster1((value) => {
    buffer1.push(value);
    if (buffer2.length) {
      listener([buffer1.shift(), buffer2.shift()]);
      if (buffer1[0] === done || buffer2[0] === done) {
        listener(done);
        cancelBoth();
      }
    }
  });

  let buffer2 = [];
  const cancel2 = broadcaster2((value) => {
    buffer2.push(value);
    if (buffer1.length) {
      listener([buffer1.shift(), buffer2.shift()]);
      if (buffer1[0] === done || buffer2[0] === done) {
        listener(done);
        cancelBoth();
      }
    }
  });
  cancelBoth = () => {
    cancel1();
    cancel2();
  };
  return cancelBoth;
});
// #endregion

// #region operators
const createOperator = curry((operator, broadcaster, listener) => {
  // new a new broadcaster and invoke original broadcaster inside new broadcaster
  return operator((behaviorListener) => {
    // override the default broadcaster
      return broadcaster(value => {
        // apply common logic
        if(value === done) {
          // stop outer listen to continue emitting values
          listener(done)
          return
        }
        // otherwise, we want to pass forward the value to listener
        behaviorListener(value)
      })
  }, listener)
})

const concat = createOperator((broadcaster, listener) => {
  let string = '';
  return broadcaster((value) => {
    listener((string += value));
  });
});

const map = transform => createOperator((broadcaster, listener) => {
  return broadcaster((value) => {
    listener(transform(value));
  });
});

const filter = predicator => createOperator((broadcaster, listener) => {
  return broadcaster((value) => {
    if (predicator(value)) {
      listener(value);
    }
  });
});

const split = splitter => curry((broadcaster, listener) => {
  let buffer = []
  return broadcaster((value) => {
    if (value === done) {
      listener(buffer)
      listener(done)
      buffer = []
    }
    if (value === splitter) {
      listener(buffer)
      buffer = []
    } else {
      buffer.push(value)
    }
  })
})
// #endregion
const transform =  pipe(
    map((x) => x[1]),
    filter((x) => x !== ','),
    map(toUpper),
    split(" ")
  );
let typeGreeting = transform(
  createZipOf(createInterval(100), createForOf('My Zipo'))
);
const cancelGreating = typeGreeting((value => {
  if(value === done) {
    _log("Shut down")
    return
  }
  _log(value)
}))
// cancelGreating()

const myZip = (boradcaster1, boradcaster2) => (...operators) => {
  return pipe(...operators)(createZipOf(boradcaster1, boradcaster2))
}
 
const typeGreeting2 = myZip(
  // boradcasters
 createInterval(100), createForOf('My Zipo')
)(
 // operators
    map((x) => x[1]),
    filter((x) => x !== ','),
    concat,
    map(toUpper)
)
const cancelGreating2 = typeGreeting2(_log)
// cancelGreating2()
复制代码

 

posted @   Zhentiw  阅读(128)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2019-10-25 [Schematics] 1. Copy and Manipulate Template
2019-10-25 [Schematics] 0. Schematics "Hello World"
2019-10-25 [RxJS] Subject asObservable() method
2019-10-25 [Flutter] Passing the data backwards thought Navigator
2018-10-25 [Unit Testing] Fundamentals of Testing in Javascript
2016-10-25 [Debug] Chrome Devtools: Elements - Console Integration
2016-10-25 [Flexbox] Use Flex to Scale Background Image
点击右上角即可分享
微信分享提示