2017-12-11 1 views
0

비동기지도 기능이 있습니다. 이 문서에서는 기존 문서가 아닌 경우 일련의 문서를 만듭니다. 첫 번째로 생성 된 문서의 ID는 다음 문서의 경우 parent으로 설정해야합니다.JS : Async/await가 루프에서 결과를 기다리는 것처럼 보이지 않습니다.

await Promise.all(data.map(async (o, index) => { 
    const key = o.name 
    const value = o.value 
    const query = { [key]: value } 
    const parentID = refID 

    console.log(parentID); 

    if (parentID) query.parent = parentID 

    // Check if document is existing 
    let ref = await References.findOne(query) 
    refID = ref ? ref._id : undefined 

    // If not existing, create it 
    if (!refID) { 
    const refInserted = await References.insertOne(query) 
    refID = refInserted ? refInserted.insertedId : undefined 
    } 

    console.log(refID) 
})) 

그래서 내가 REFID와 parentID 교류와 함께이 로그 출력을 기대 :

undefined (parentID first run) 
yBZWYJcWBoSzx9qwy (refID first run) 
yBZWYJcWBoSzx9qwy (parentID second run) 
23poGAbg85LCqkcZc (refID second run) 
23poGAbg85LCqkcZc (parentID third run) 
yBJYzedxftLe2Xm4r (refID third run) 
yBJYzedxftLe2Xm4r (parentID fourth run) 
PpzjuZ4vfrktNH4ez (refID fourth run) 

을하지만 어떻게해야합니까는 로그 출력을 번갈아되지 않는다는 것을 나에게 보여

undefined 
undefined 
undefined 
undefined 
undefined 
undefined 
yBZWYJcWBoSzx9qwy 
23poGAbg85LCqkcZc 
yBJYzedxftLe2Xm4r 
PpzjuZ4vfrktNH4ez 

, 그러나 두 블록으로 실행하고 있는데 insertOne (몽고 네이티브 드라이버 사용)에 대해 await을 설정했습니다. 그래서 분명히 내가 뭔가를 오해하고있어 :

제가 생각하기에, 그게 map입니다 -이 경우 - forEach 루프와 같습니다 : 처음 실행하면 기존 문서의 ID 또는 ID 새롭게 생성 된 문서 (나가지 않은 경우)가 추출됩니다. 두 번째 실행에서이 ID는 parentID로 설정되므로 두 번째로 생성 된 문서의 경우 상위 키가 설정됩니다.

답변

2

여기에있는 문제는 평가를 동기화하려는 경우 Promise.all을 사용하지 않으려한다는 것입니다. Promise.all은 일련의 약속을 수락하고 약속이 언제든지 해결되도록 허용하기 때문입니다. 대신 비동기 함수로 작업을 래핑 한 다음 기존 루프를 사용하십시오.

async function processData(data){ 
    for (var index = data.length - 1; i >= 0; i--) { 
     const o = data[index]; 
     const key = o.name 
     const value = o.value 
     const query = { [key]: value } 
     const parentID = refID 

     console.log(parentID); 

     if (parentID) query.parent = parentID 

     // Check if document is existing 
     let ref = await References.findOne(query) 
     refID = ref ? ref._id : undefined 

     // If not existing, create it 
     if (!refID) { 
      const refInserted = await References.insertOne(query) 
      refID = refInserted ? refInserted.insertedId : undefined 
     } 

     console.log(refID) 
    } 
} 
2

사용자가 의도 한대로 실제로 작동하는지 알 수 있습니다. 로그 출력을 보는 이유는 계속 이동하기 전에 배열의 각 항목에 대해 맵 함수의 첫 번째 '단계'(다음 대기 호출까지의 코드)를 실행하기 때문입니다. 각 항목에 대한 위상이 개별적으로 순차적으로 실행할 수 있습니다 것입니다 동안

var arr = [1,2,3,4,5] 
 

 
function timer(dur) { 
 
    return new Promise(res => { 
 
    setTimeout(res, dur); 
 
    }); 
 
} 
 

 
async function doStuff() { 
 
    console.log("Beginning block...") 
 

 
    await Promise.all(arr.map(async (x) => { 
 
    console.log("Starting phase 1 for item:", x); 
 
    await timer(500); 
 
    console.log("Phase 1 complete, starting phase 2 for item:", x); 
 
    await timer(500); 
 
    console.log("Phase 2 complete for item:", x); 
 
    })); 
 

 
    console.log("Block ended...") 
 
} 
 

 
doStuff()
그래서, 동일 전체 컬렉션에 대한 사실이 아니다 :

이 조각을 참조하십시오. 예를 들어, 단계 1은 그 중 하나에 대해 완료되기 전에 각각에 대해 시작됩니다. 이는 map이 동기이지만 실제로 전달하는 함수의 결과가 아닙니다.

당신은 절대적으로 이동하기 전에 항목에 대한 완전한 모든 단계, 당신은 Promise.all을 사용하지 않고, 개별적으로 각각을 기다리고해야합니다 것을 적용하려면 :

var arr = [1,2,3,4,5] 
 

 
function timer(dur) { 
 
    return new Promise(res => { 
 
    setTimeout(res, dur); 
 
    }); 
 
} 
 

 
async function doStuff() { 
 
    console.log("Beginning block...") 
 

 
    for (const x of arr) { 
 
    console.log("Starting phase 1 for item:", x); 
 
    await timer(500); 
 
    console.log("Phase 1 complete, starting phase 2 for item:", x); 
 
    await timer(500); 
 
    console.log("Phase 2 complete for item:", x); 
 
    }; 
 

 
    console.log("Block ended...") 
 
} 
 

 
doStuff()

하지만 당신을 각 항목을 더 이상 병렬로 실행할 수 없기 때문에이 작업을 완료하는 데 걸리는 시간이 상당히 길다는 점에 유의하십시오.

관련 문제