2016-12-20 1 views
12

그래서 같은) 비동기를 통합하는 문제도/.reduce (함께 기다리고있을 것 같다 :스크립트 배열 .reduce와 비동기/AWAIT

const data = await bodies.reduce(async(accum, current, index) => { 
    const methodName = methods[index] 
    const method = this[methodName] 
    if (methodName == 'foo') { 
    current.cover = await this.store(current.cover, id) 
    console.log(current) 
    return { 
     ...accum, 
     ...current 
    } 
    } 
    return { 
    ...accum, 
    ...method(current.data) 
    } 
}, {}) 
console.log(data) 

data 객체 전에 this.store 완료를 기록한다 ..

Promise.all을 비동기 루프와 함께 사용할 수 있다는 것을 알고 있지만, .reduce()에 해당합니까?

답변

21

문제는 축약 값이 약속임을 의미합니다. 반환 값은 async function입니다. 순차적 인 평가를 얻기 위해 (그리고 마지막 반복하지만 모든 전혀 기다려온 할), 당신은 그들이 더 확대됨에이고, 나는 일반에서와 use plain loops instead of array iteration methods에게 추천 async/await에 대해 말했다

const data = await array.reduce(async (accumP, current, index) => { 
    const accum = await accumP; 
    … 
}, Promise.resolve(…)); 

을 사용할 필요가 종종 더 간단합니다.

+1

감사를 말 . 내가하고있는 일에 대해 단순한 for 루프를 사용하여 끝내었지만, 코드와 같은 줄 이었지만 읽는 것이 훨씬 쉬웠다. ... –

+0

'reduce'의'initialValue'는'Promise ', 그러나 그것은 대부분의 경우에 의도를 분명히 할 것이다. – EECOLOR

+0

@EECOLOR 그래야합니다. 나는 평범한 가치를 약속으로 던지기를 정말로 싫어한다. – Bergi

1

전체 맵을 감싸거나 반복기 블록을 자체 Promise.resolve로 축소하고 완료 할 때까지 기다릴 수 있습니다. 그러나 문제는 누적 기가 각 반복에서 예상되는 결과 데이터/오브젝트를 포함하지 않는다는 것입니다. 내부 async/await/Promise 체인으로 인해 누적 기가 실제 가게에 전화하기 전에 await 키워드를 사용 했음에도 불구하고 스스로 해결할 가능성이 거의 없음을 약속합니다 (이로 인해 반복이 실제로 그래서하자로 그 호출이 완료되고 축적이 업데이트 될 때까지 돌아갑니다.

를이 가장 우아한 해결책은 아니지만, 당신은 하나의 옵션은 범위에서 당신의 데이터 개체 변수를 이동하고 할당하는 것입니다 적절한 바인딩 및 변형이 발생할 수 있습니다. 그런 다음 async/await/Promise 호출이 해결 될 때 반복기 내부에서이 데이터 객체를 업데이트하십시오.

/* allow the result object to be initialized outside of scope 
    rather than trying to spread results into your accumulator on iterations, 
    else your results will not be maintained as expected within the 
    internal async/await/Promise chain. 
*/  
let data = {}; 

await Promise.resolve(bodies.reduce(async(accum, current, index) => { 
    const methodName = methods[index] 
    const method = this[methodName]; 
    if (methodName == 'foo') { 
    // note: this extra Promise.resolve may not be entirely necessary 
    const cover = await Promise.resolve(this.store(current.cover, id)); 
    current.cover = cover; 
    console.log(current); 
    data = { 
     ...data, 
     ...current, 
    }; 
    return data; 
    } 
    data = { 
    ...data, 
    ...method(current.data) 
    }; 
    return data; 
}, {}); 
console.log(data); 
0

나는 Bergi의 대답을 좋아한다. 나는 그것이 올바른 방향이라고 생각한다. 나는 또한 내 라이브러리를 언급하고 싶습니다

async/await 당신은 쉽게 reduce 같은 기능을 사용할 수 있습니다 Awaity.js

, map & filter라고 : 당신의 조언을

import reduce from 'awaity/reduce'; 

const posts = await reduce([1,2,3], async (posts, id) => { 
    const res = await fetch('/api/posts/' + id); 
    const post = res.json(); 

    return { 
    ...posts, 
    [id]: post 
    } 
}, {}) 

posts // { 1: { ... }, 2: { ... }, 3: { ... } }