简体   繁体   中英

Best way to write a function that either returns a value, or a resolved promise

So I am trying to write a logging HOC that will take a function and log the result of that function. I would like this hoc to be able to log the result of any function whether that function returns a promise or a value. This is what I have so far:

const logFn = (x) => {
  return   (...args) => {
    const result =  x(...args);
    console.log(`result: ${result}`);
    return result;
  }
};

I would like to have this function handle the case when x returns a promise. I know a hacky way to do it (typeof result === object && typeof result.then === function) but this seems brittle. I am nearly sure there is a more elegant way to do this but I am struggling to find it.

I have included a failing jest test below:

import logFn from './logFn';

describe('logFn', () => {

  let outputData;
  beforeEach(() => {
    const storeLog = inputs => (outputData += inputs);
    console["log"] = jest.fn(storeLog);
    require('./logFn');
    outputData = ""
  });


  it('handles async functions', () => {
    const add2P = (x, y) => Promise.resolve(x + y);
    const logAdd2 = logFn(add2P);
    const expected = add2P(1,2).then((data) => data);
    const actual = logAdd2(1,2);

    expect(outputData).toBe('result: 3');
    expect(actual).toEqual(expected);
  })
});

bonus points if you can help me clean up the beforeEach.

This has the unfortunate side effect of not logging synchronously, but you could try this.

const logFn = (x) => {
  return   (...args) => {
    const result =  x(...args);
    Promise.resolve(result).then(function(value) {
     console.log(`result: ${value}`);
    })
    return result;
  }
};

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve

While this answer isn't much different from @lemieuxster's answer , there is one major difference.

const logFn = fn => function () {
  const result = fn.apply(this, arguments);
  Promise.resolve(result).then(value => { console.log(`result: ${value}`); });
  return result;
};

This preserves the calling context if, for example, you want to logify member methods:

 const logFn = fn => function () { const result = fn.apply(this, arguments); Promise.resolve(result).then(value => { console.log(`result: ${value}`); }); return result; }; const foo = { bar: 'Hello, world!', doSomething: logFn(function () { return this.bar; }) }; foo.doSomething(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM