We refactor a function that uses try/catch to a single composed expression using Either. We then introduce the chain function to deal with nested Eithers resulting from two try/catch calls.

For example we have this code using try & catch:

  1. const getPort = () => {
  2. try {
  3. const file = fs.readFileSync('config.json');
  4. const c = JSON.parse(file);
  5. return c.port;
  6. } catch(e) {
  7. return ;
  8. }
  9. }

And now, we want to use Either to rewirte the code:

  1. // SETUP: fake fs
  2. //==========
  3. const fs = {
  4. readFileSync: name => {
  5. if(name === 'config.json') {
  6. return JSON.stringify({port: })
  7. } else {
  8. throw('missing file!')
  9. }
  10. }
  11. }
  12.  
  13. //=================
  14.  
  15. const Right = x => ({
  16. map: f => Right(f(x)),
  17. fold: (f, g) => g(x),
  18. toString: () => `Right(${x})`
  19. });
  20.  
  21. const Left = x => ({
  22. map: f => Left(x),
  23. fold: (f, g) => f(x),
  24. toString: () => `Left(${x})`
  25. });
  26.  
  27. const fromNullable = x =>
  28. x != null ? Right(x): Left(null);
  29.  
  30. const tryCatch = f => {
  31. try {
  32. return Right(f());
  33. } catch(e) {
  34. return Left(e);
  35. }
  36. }
  37.  
  38. //=========================
  39. const getPort = () =>
  40. tryCatch(() => fs.readFileSync('config.json'))
  41. .map(f => JSON.parse(f))
  42. .fold(
  43. x => ,
  44. x => x.port);
  45.  
  46. console.log(getPort('config.json'))

We wrote the function 'tryCatch', the idea is put the code need to be checked in try, when success call 'Right', error, call 'Left()'.

  1. tryCatch(() => fs.readFileSync('config.json'))

Read the file, is success, will return file content. If not, then goes to set default 3000.

  1. .fold(
  2. x => ,
  3. x => x.port);

It works, but we still miss one things, in the old code, the 'JSON.parse' are also wrapped into try catch.

  1. const getPort = () =>
  2. tryCatch(() => fs.readFileSync('config.json')) //Right('{port:8888}')
  3. .map(f => tryCatach(() => JSON.parse(f))) //Right(Right({port:8888}))

But once we also wrap parseing code into tryCatch function, the return value is 2d-Right. So we want to flatten it.

  1. const Right = x => ({
  2. map: f => Right(f(x)),
  3. flatMap: f => f(x),
  4. fold: (f, g) => g(x),
  5. toString: () => `Right(${x})`
  6. });
  7.  
  8. const Left = x => ({
  9. map: f => Left(x),
  10. flatMap: f => f(x),
  11. fold: (f, g) => f(x),
  12. toString: () => `Left(${x})`
  13. });

We add 'flatMap', so instead of putting the value into Right() or Left(), we just return the value. Because we know the value passed in is already a Right or Left.

  1. const getPort = () =>
  2. tryCatch(() => fs.readFileSync('config.json')) //Right('{port:8888}')
  3. .flatMap(f => tryCatch(() => JSON.parse(f))) //Right({port:8888})
  4. .fold(
  5. x => ,
  6. x => x.port);

---------

  1. // SETUP: fake fs
  2. //==========
  3. const fs = {
  4. readFileSync: name => {
  5. if(name === 'config.json') {
  6. return JSON.stringify({port: })
  7. } else {
  8. throw('missing file!')
  9. }
  10. }
  11. }
  12.  
  13. //=================
  14.  
  15. const Right = x => ({
  16. map: f => Right(f(x)),
  17. flatMap: f => f(x),
  18. fold: (f, g) => g(x),
  19. toString: () => `Right(${x})`
  20. });
  21.  
  22. const Left = x => ({
  23. map: f => Left(x),
  24. flatMap: f => f(x),
  25. fold: (f, g) => f(x),
  26. toString: () => `Left(${x})`
  27. });
  28.  
  29. const fromNullable = x =>
  30. x != null ? Right(x): Left(null);
  31.  
  32. const tryCatch = f => {
  33. try {
  34. return Right(f());
  35. } catch(e) {
  36. return Left(e);
  37. }
  38. }
  39.  
  40. //=========================
  41. const getPort = () =>
  42. tryCatch(() => fs.readFileSync('config.json')) //Right({port:8888})
  43. .flatMap(f => tryCatch(() => JSON.parse(f))) //Right(Right({port:8888}))
  44. .fold(
  45. x => ,
  46. x => x.port);
  47.  
  48. console.log(getPort('config.json'))

-----

You can also rename 'flatMap' to 'chain'. Sometime 'flatMap' or 'chain' looks similar to 'fold' implementation. But the meaning is different, here 'chain / flatMap' says It says, "If we're going to return another Either, we are going to use chain instead of map." 'fold' says just get the value out of the box, it's done!

[JS Compose] 3. Use chain for composable error handling with nested Eithers (flatMap)的更多相关文章

  1. JS function document.onclick(){}报错Syntax error on token "function", delete this token

    JS function document.onclick(){}报错Syntax error on token "function", delete this token func ...

  2. JS function document.onclick(){}报错Syntax error on token "function", delete this token - CSDN博客

    原文:JS function document.onclick(){}报错Syntax error on token "function", delete this token - ...

  3. Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions

    The ideal time to catch an error is at compile time, before you even try to run the program. However ...

  4. Erlang error handling

    Erlang error handling Contents Preface try-catch Process link Erlang-way error handling OTP supervis ...

  5. MySQL Error Handling in Stored Procedures 2

    Summary: this tutorial shows you how to use MySQL handler to handle exceptions or errors encountered ...

  6. setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto

    目录 . 应用场景 . Use Case Code Analysis . 和setjmp.longjmp有关的glibc and eglibc 2.5, 2.7, 2.13 - Buffer Over ...

  7. Error Handling

    Use Exceptions Rather Than Return Codes Back in the distant past there were many languages that didn ...

  8. Error Handling and Exception

    The default error handling in PHP is very simple.An error message with filename, line number and a m ...

  9. Clean Code–Chapter 7 Error Handling

    Error handling is important, but if it obscures logic, it's wrong. Use Exceptions Rather Than Return ...

随机推荐

  1. FastReport.Net使用:[9]多栏报表(多列报表)

    方法一:使用页的列属性(Page Columns) 1.绘制报表标题 2.设置页的列数量为3,其他默认不变.报表设计界面便如下呈现. 3.报表拷贝前面[分组]报表的内容. 4.就这么简单,一张多栏报表 ...

  2. [CODE FESTIVAL 2018]Sushi Restaurant

    题意:有$n$个人,对每个人,他有$p_i$的概率饥饿值为$x_i$($1\leq i\leq m$),你现在要做$n$盘寿司,每盘寿司有一定的数量,当这$n$个人的饥饿值确定后他们会自己选择最优的( ...

  3. easyui 属性集合

    easyUI属性汇总 属性分为CSS片段和JS片段. CSS类定义:1.div easyui-window 生成一个window窗口样式. 属性如下: 1)modal:是否生成模态窗口.true[是] ...

  4. CDOJ 1048 Bob's vector 三分

    Bob's vector 题目连接: http://acm.uestc.edu.cn/#/problem/show/1048 Description Bob has a vector with mm ...

  5. VK Cup 2016 - Qualification Round 1 (Russian-Speaking Only, for VK Cup teams) C. Promocodes with Mistakes 水题

    C. Promocodes with Mistakes 题目连接: http://www.codeforces.com/contest/637/problem/C Description During ...

  6. php 安装 Redis 扩展

    开发环境安装包为:wamp3.1.0,安装成功后 wamp/bin 目录下有php以下几个版本: 这里以php7.1.9为例进行redis扩展安装,其他php版本也是一样的. 进行安装 step 1: ...

  7. linux基础命令学习(二)文件和目录操作

    1.变换当前目录(change directory)     cd /home 进入 '/ home' 目录'  (change directory)   cd .. 返回上一级目录    cd .. ...

  8. 将多层级xml解析为Map

    /** * 解析xml的工具类 * 1.将多层级xml解析为Map */ public class ParseXmlUtil { public static final String TAG = &q ...

  9. Use an LM317 as 0 to 3V adjustable regulator

    Most engineers know that they can use an inexpensive, three-terminal adjustable regulator, such as F ...

  10. JavaScript如何获取/计算页面元素的offset?

    问题  通过点击一控件,在控件的下面显示一个浮动层,通常的做法是:获取此控件的offset值,再计算出浮动层的top,left等css属性的值,赋值即可. 那么下面就看一下如何获取控件的offset值 ...