【问题标题】:how to use promise function in javascript functional function like forEach reduce?如何在forEach reduce等javascript函数中使用promise函数?
【发布时间】:2016-08-16 06:59:35
【问题描述】:

我正在使用这样的 promise 函数:

// WORK
let res = {approveList: [], rejectList: [], errorId: rv.errorId, errorDesc: rv.errorDesc};
for (let i = 0; i < rv.copyDetailList.length; i ++) {
    const item = rv.copyDetailList[i];
    const v = await convertCommonInfo(item);
    if (!item.errorId) {
        res.approveList.push(v);
    } else {
        res.rejectList.push(merge(v, {errorId: item.errorId, errorDesc: item.errorMsg}));
    }
}

这个很好用,但是我想尝试使用一些功能函数,我发现我必须使用map然后reduce

// WORK, But with two traversal
const dataList = await promise.all(rv.copyDetailList.map((item) => convertCommonInfo(item)));

const res = dataList.reduce((obj, v, i) => {
    const item = rv.copyDetailList[i];
    if (!item.errorId) {
        obj.approveList.push(v);
    } else {
        obj.rejectList.push(merge(v, {errorId: item.errorId, errorDesc: item.errorMsg}));
    }

    return obj;
}, {approveList: [], rejectList: [], errorId: rv.errorId, errorDesc: rv.errorDesc});

我发现forEach函数不能工作:

// NOT WORK, not wait async function
rv.copyDetailList.forEach(async function(item) {
    const v = await convertCommonInfo(item);
    if (!item.errorId) {
        res.approveList.push(v);
    } else {
        res.rejectList.push(merge(v, {errorId: item.errorId, errorDesc: item.errorMsg}));
    }
});

这不起作用,它只是返回初始值。 其实这让我很困惑,因为我await的功能,为什么不工作?

连我都想用reduce函数:

// NOT WORK, Typescirpt can not compile
rv.copyDetailList.reduce(async function(prev, item) {
    const v = await convertCommonInfo(item);
    if (!item.errorId) {
        prev.approveList.push(v);
    } else {
        prev.rejectList.push(merge(v, {errorId: item.errorId, errorDesc: item.errorMsg}));
    }
}, res);

但是由于我使用的是Typescript,所以我得到了这样的错误:

error TS2345: Argument of type '(prev: { approveList: any[]; rejectList: any[]; errorId: string; errorDesc: string; }, item: Resp...' is not assignable to parameter of type '(previousValue: { approveList: any[]; rejectList: any[]; errorId: string; errorDesc: string; }, c...'.
Type 'Promise<void>' is not assignable to type '{ approveList: any[]; rejectList: any[]; errorId: string; errorDesc: string; }'.
Property 'approveList' is missing in type 'Promise<void>'.

所以我想知道两件事:

  1. 为什么forEachawait 不起作用?
  2. 可以在reduce中使用promise函数吗?

【问题讨论】:

标签: javascript typescript functional-programming promise async-await


【解决方案1】:

您可能正在倒退。通常,您希望使用compose 组合所有转换并将组合函数传递给promise 的.then 处理程序:

// assumes curried times and add functions
let tranformData = _.compose(square, times(2), add(3));

let foo = fetchNumberAsync() // returns a promise of 3
  .then(transformData)
  .catch(err => doSomethingWithError(err));

foo.then(n => console.log(n)); // prints 144 to the console ((3 + 3) * 2) ** 2

比较替代方案:

// clear but wasteful
let foo = fetchNumberAsync()
  .then(n => n + 3)
  .then(n => n * 2)
  .then(n => n ** 2)

// performant but opaque
let foo = fetchNumberAsync().then(n => ((n + 3) * 2) ** 2)

使用compose(尤其是memoize)是一个很好的中间道路。

【讨论】:

    【解决方案2】:

    为什么 forEach await 不能工作? 您为 forEach 提供了一个异步函数,但在 forEach 函数的实现中,它没有被等待。我猜forEach是这样的:

    Array.prototype.forEach = function (func) {
        for (let item of this) {
            func(item);    // Note here, there is no "await" in front of it 
        }
    }
    

    我可以在reduce中使用promise函数吗? 不,你不能和上面的理由一样。

    通过“co”来平滑代码的另一种方法如下:

    let ret = await rv.copyDetailList.map(co(function * (item) {
        const v = yield convertCommonInfo(item);
        if (!item.errorId) {
            res.approveList.push(v);
        } else {
            res.rejectList.push(merge(v, {errorId: item.errorId, errorDesc: item.errorMsg}));
        }
    }));
    

    【讨论】:

      【解决方案3】:

      如果您的最终目标是实现每次迭代同时运行的单次遍历,那么有各种可用的库可以提供 “每个异步”,就像您所说的那样正在寻找。

      async-parallel 就是一个这样的库,它提供了一个 Parallel.each 迭代器,可以很好地与 async/await 配合使用。

      使用这个库,您的代码可能看起来像这样......

      let res = {approveList: [], rejectList: [], errorId: rv.errorId, errorDesc: rv.errorDesc};
      await Parallel.each(rv.copyDetailList, async (item) => {
          var v = await convertCommonInfo(item);
          if (!item.errorId)
              res.approveList.push(v);
          else
              res.rejectList.push(merge(v, {errorId: item.errorId, errorDesc: item.errorMsg}));
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多