如何在javascript函数函数中使用promise函数,如forEach reduce?

时间:2016-08-16 06:59:35

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

我正在使用这样的承诺函数:

// 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然后减少

// 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. 为什么forEach等待不起作用?
  2. 我可以在reduce中使用promise函数吗?

3 个答案:

答案 0 :(得分: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)是一条很好的中途道路。

答案 1 :(得分:1)

为什么每个等待都无法正常工作? 您为forEach提供了一个异步函数,但在forEach函数的实现中,它是不等的。我想forEach是这样的:

<img src="prof.jpg" id="pictureToShow" />

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

通过“co”来替代代码的替代方法如下所示:

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

答案 2 :(得分:1)

如果您的最终目标是实现每次迭代同时运行的单个遍历,那么可以使用各种库来提供&#34;异步的每个&#34; 沿着它的行听起来像你正在寻找。

一个这样的库是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}));
});