[JS Compose] 3. Use chain for composable error handling with nested Eithers (flatMap)

Posted Answer1215

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JS Compose] 3. Use chain for composable error handling with nested Eithers (flatMap)相关的知识,希望对你有一定的参考价值。

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:

const getPort = () => {
  try {
    const file = fs.readFileSync(config.json);
    const c = JSON.parse(file);
    return c.port;
  } catch(e) {
    return 3000;
  }
}

 

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

// SETUP: fake fs
//==========
const fs = {
  readFileSync: name => {
    if(name === config.json) {
      return JSON.stringify({port: 8888})
    } else {
      throw(missing file!)
    }
  }
}

//=================

const Right = x => ({
    map: f => Right(f(x)),
    fold: (f, g) => g(x),
    toString: () => `Right(${x})`
  });

const Left = x => ({
  map: f => Left(x),
  fold: (f, g) => f(x),
  toString: () => `Left(${x})`
});

const fromNullable = x => 
  x != null ? Right(x): Left(null);

const tryCatch = f => {
  try {
    return Right(f());
  } catch(e) {
    return Left(e);
  }
}

//=========================
const getPort = () =>
  tryCatch(() => fs.readFileSync(config.json))
  .map(f => JSON.parse(f))
  .fold(
    x => 3000,
    x => x.port);

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()‘.

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

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

  .fold(
    x => 3000,
    x => x.port);

 

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

const getPort = () =>
  tryCatch(() => fs.readFileSync(config.json)) //Right(‘{port:8888}‘)
  .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.

 

const Right = x => ({
    map: f => Right(f(x)),
    flatMap: f => f(x),
    fold: (f, g) => g(x),
    toString: () => `Right(${x})`
  });

const Left = x => ({
  map: f => Left(x),
  flatMap: f => f(x),
  fold: (f, g) => f(x),
  toString: () => `Left(${x})`
});

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.

 

const getPort = () =>
  tryCatch(() => fs.readFileSync(config.json)) //Right(‘{port:8888}‘)
  .flatMap(f => tryCatch(() => JSON.parse(f))) //Right({port:8888})
  .fold(
    x => 3000,
    x => x.port);

 

 

---------

// SETUP: fake fs
//==========
const fs = {
  readFileSync: name => {
    if(name === config.json) {
      return JSON.stringify({port: 8888})
    } else {
      throw(missing file!)
    }
  }
}

//=================

const Right = x => ({
    map: f => Right(f(x)),
    flatMap: f => f(x),
    fold: (f, g) => g(x),
    toString: () => `Right(${x})`
  });

const Left = x => ({
  map: f => Left(x),
  flatMap: f => f(x),
  fold: (f, g) => f(x),
  toString: () => `Left(${x})`
});

const fromNullable = x => 
  x != null ? Right(x): Left(null);

const tryCatch = f => {
  try {
    return Right(f());
  } catch(e) {
    return Left(e);
  }
}

//=========================
const getPort = () =>
  tryCatch(() => fs.readFileSync(config.json)) //Right({port:8888})
  .flatMap(f => tryCatch(() => JSON.parse(f))) //Right(Right({port:8888}))
  .fold(
    x => 3000,
    x => x.port);

console.log(getPort(config.json))

 

以上是关于[JS Compose] 3. Use chain for composable error handling with nested Eithers (flatMap)的主要内容,如果未能解决你的问题,请参考以下文章

Rxjava操作符compose

html JS-方法-chaining.html

[Compose] 21. Apply Natural Transformations in everyday work

利用jquery.chained.remote实现多级级联

docker address already in use

@babel/plugin-proposal-optional-chaining 在 Vue.js <script> 标签中不起作用