javascript 虚线Map值异步

vq8itlhq  于 2023-02-02  发布在  Java
关注(0)|答案(4)|浏览(167)

在_.mapValues内部,我想获得一些修改过的值,但有一些延迟(例如从DB),但我遇到了问题:当我在同步模式下修改值时,一切都很好,当我尝试错误地使用承诺或回调其工作时(在第一种情况下,我得到了承诺对象,在第二种情况下:下面是一些简单的例子,我如何在mapValues中重写代码来解决这个问题?

'use strict';
const _ = require('lodash');
const Promise = require('bluebird');

let obj = {
  one: 1,
  two: 2,
};

let increment = (value) => {
  return value + 1;
};

let incrementProm = (value) => {
  return Promise.resolve(value + 1);
};

let incrementCb = (value, cb) => {
  let res = value + 1;
  let err = null;
  setTimeout(cb.bind(undefined, err, res), 100);
};

let t1 = _.mapValues(obj, (value) => {
  return increment(value);
});

let t2 = _.mapValues(obj, (value) => {
  return incrementProm(value);
});

let t3 = _.mapValues(obj, (value) => {
  let temp;
  incrementCb(value, (err, res) => {
    temp = res;
  });
  return temp;
});

console.log('Sync res:');
console.log(t1);
console.log('Promise res:');
console.log(t2);
console.log('Callback res:');
console.log(t3);
v9tzhpje

v9tzhpje1#

可以使用bluebird的props()函数解析所有带有promise的属性。

Promise.props(_.mapValues(obj, incrementProm))
.then(result => console.log(result));

x一个一个一个一个x一个一个二个x

vfh0ocws

vfh0ocws2#

你在Map承诺,所以我可能会做些什么:

var _ = require('lodash');
let incrementProm = (value) => {
  return Promise.resolve(value + 1);
};

let obj = {
    foo: 1,
    bar: 2
}

let keys = _.keys(obj);
let promises = _.map(keys, k => {
    return incrementProm(obj[k])
    .then(newValue => { return { key: k, value: newValue } });
})
Promise.all(promises).then(values => {
    values.forEach(v => obj[v.key] = v.value)
})
.then(() => {
    // now your object is updated: foo = 2 and bar = 3
    console.log(obj);
});
whitzsjs

whitzsjs3#

你可以实现一个mapValues的异步版本。

async function mapValuesAsync(object, asyncFn) {
  return Object.fromEntries(
    await Promise.all(
      Object.entries(object).map(async ([key, value]) => [
        key,
        await asyncFn(value, key, object)
      ])
    )
  );
}

然后像调用_.mapValues一样调用它:

let t2 = await mapValuesAsync(obj, (value) => {
    return incrementProm(value);
});

或者简单地说

let t2 = await mapValuesAsync(obj, incrementProm);
368yc8dk

368yc8dk4#

下面是一个TypeScript解决方案,构建在lodash函数之上:

import { fromPairs, toPairs, ObjectIterator } from 'lodash';

export async function mapValuesAsync<T extends object, TResult>(
  obj: T | null | undefined,
  callback: ObjectIterator<T, Promise<TResult>>,
): Promise<{ [P in keyof T]: TResult }> {
  return fromPairs(
    await Promise.all(
      toPairs(obj).map(async ([key, value]) => [
        key,
        await callback(value, key, obj),
      ]),
    ),
  ) as { [P in keyof T]: TResult };
}

如果您不需要类型,下面是JavaScript版本:

import { fromPairs, toPairs } from 'lodash';

export async function mapValuesAsync(obj, callback) {
  return fromPairs(
    await Promise.all(
      toPairs(obj).map(async ([key, value]) => [
        key,
        await callback(value, key, obj),
      ]),
    ),
  );
}

如果你需要的话,这里有一个测试:

import { mapValuesAsync } from './map-values-async';

describe('mapValuesAsync', () => {
  it('should map values with an async callback', async () => {
    const result = await mapValuesAsync(
      {
        a: 1,
        b: 2,
      },
      async (value) => {
        return await Promise.resolve(value * 2);
      },
    );

    const expected = {
      a: 2,
      b: 4,
    };
    expect(result).toEqual(expected);
  });
});

这是受到了Rui Castro回应的启发,Rui Castro巧妙地使用了Object.entriesObject.fromEntries。然而,这需要es2019或更高版本才能工作。Lodash有等效的函数toPairsfromPairs,它们可以与任何风格的JavaScript一起工作。

相关问题