programing

노드 JS 약속.모두에 대하여

iphone6s 2023. 10. 24. 20:16
반응형

노드 JS 약속.모두에 대하여

저는 비동기 방식을 노출하는 배열과 같은 구조를 가지고 있습니다.비동기 메서드는 리턴 배열 구조를 호출하여 더 많은 비동기 메서드를 표시합니다.저는 이 구조에서 얻은 값을 저장하기 위해 또 다른 JSON 개체를 생성하고 있으므로 콜백에서 참조를 추적하는 데 주의해야 합니다.

브루트 포스 솔루션을 코딩했지만, 좀 더 관용적이거나 깨끗한 솔루션을 배우고 싶습니다.

  1. 패턴은 n개 수준의 중첩에 대해 반복 가능해야 합니다.
  2. 약속이 필요합니다.모두 또는 어떤 유사한 기술을 사용하여 엔클로저 루틴을 해결할 시기를 결정합니다.
  3. 모든 요소가 반드시 비동기 호출을 포함하는 것은 아닙니다.그래서 중첩된 약속에서.인덱스를 기반으로 JSON 배열 요소를 단순하게 할당할 수 없습니다.그럼에도 불구하고, 약속 같은 것을 사용할 필요가 있습니다.Enclosing 루틴을 해결하기 전에 모든 속성 할당이 수행되었는지 확인하기 위해 each에 대해 모두 nested됩니다.
  4. 파랑새 약속 lib를 사용하고 있지만 이는 필수 사항이 아닙니다.

여기 부분 코드가 있습니다.

var jsonItems = [];

items.forEach(function(item){

  var jsonItem = {};
  jsonItem.name = item.name;
  item.getThings().then(function(things){
  // or Promise.all(allItemGetThingCalls, function(things){

    things.forEach(function(thing, index){

      jsonItems[index].thingName = thing.name;
      if(thing.type === 'file'){

        thing.getFile().then(function(file){ //or promise.all?

          jsonItems[index].filesize = file.getSize();

몇 가지 간단한 규칙을 사용하면 매우 간단합니다.

  • 에서 약속을 만들 때마다, 약속을 반환하십시오. 반환하지 않는 약속은 밖에서 기다리지 않습니다.
  • 여러 개의 약속을 만들 때마다 모든 약속을 기다리는 방식으로 모든 약속을 묵살할 수 있습니다.
  • 둥지를 틀 마다 보통 중간에 돌아올있습니다.then체인들은 보통 최대 1단계 깊이입니다.
  • IO를 수행할 때는 항상 약속이 있어야 합니다. 약속이 있어야 하거나 완료를 알리는 약속이 있어야 합니다.

그리고 몇 가지 팁:

  • 함수를 사용하여 값을 매핑하는 경우보다 매핑을 수행하는 것이 더 좋습니다.map작업을 하나씩 적용하고 결과를 집계하는 개념을 간결하게 표현할 수 있습니다.
  • 동시 실행이 무료일 경우 순차 실행보다 낫습니다. 동시 실행하고 기다리는 것이 좋습니다.Promise.all하나씩 차례로 실행하는 것보다, 각자가 다음 순서를 기다리는 것보다.

자, 그럼 시작하겠습니다.

var items = [1, 2, 3, 4, 5];
var fn = function asyncMultiplyBy2(v){ // sample async action
    return new Promise(resolve => setTimeout(() => resolve(v * 2), 100));
};
// map over forEach since it returns

var actions = items.map(fn); // run the function over all items

// we now have a promises array and we want to wait for it

var results = Promise.all(actions); // pass array of promises

results.then(data => // or just .then(console.log)
    console.log(data) // [2, 4, 6, 8, 10]
);

// we can nest this of course, as I said, `then` chains:

var res2 = Promise.all([1, 2, 3, 4, 5].map(fn)).then(
    data => Promise.all(data.map(fn))
).then(function(data){
    // the next `then` is executed after the promise has returned from the previous
    // `then` fulfilled, in this case it's an aggregate promise because of 
    // the `.all` 
    return Promise.all(data.map(fn));
}).then(function(data){
    // just for good measure
    return Promise.all(data.map(fn));
});

// now to get the results:

res2.then(function(data){
    console.log(data); // [16, 32, 48, 64, 80]
});

축소를 사용한 간단한 예는 다음과 같습니다.직렬로 실행되며 삽입 순서를 유지하며 Bluebird가 필요하지 않습니다.

/**
 * 
 * @param items An array of items.
 * @param fn A function that accepts an item from the array and returns a promise.
 * @returns {Promise}
 */
function forEachPromise(items, fn) {
    return items.reduce(function (promise, item) {
        return promise.then(function () {
            return fn(item);
        });
    }, Promise.resolve());
}

그리고 이렇게 사용합니다.

var items = ['a', 'b', 'c'];

function logItem(item) {
    return new Promise((resolve, reject) => {
        process.nextTick(() => {
            console.log(item);
            resolve();
        })
    });
}

forEachPromise(items, logItem).then(() => {
    console.log('done');
});

선택적 컨텍스트를 루프로 전송하는 것이 유용하다는 것을 알게 되었습니다.컨텍스트는 선택사항이며 모든 반복에서 공유됩니다.

function forEachPromise(items, fn, context) {
    return items.reduce(function (promise, item) {
        return promise.then(function () {
            return fn(item, context);
        });
    }, Promise.resolve());
}

약속 기능은 다음과 같습니다.

function logItem(item, context) {
    return new Promise((resolve, reject) => {
        process.nextTick(() => {
            console.log(item);
            context.itemCount++;
            resolve();
        })
    });
}

저도 같은 상황을 겪었습니다.저는 두 가지 약속을 이용해서 풀었습니다.모두().

정말 좋은 해결책이었던 것 같아 npm: https://www.npmjs.com/package/promise-foreach 에 게시했습니다.

당신의 코드는 이런 것이 될 것 같습니다.

var promiseForeach = require('promise-foreach')
var jsonItems = [];
promiseForeach.each(jsonItems,
    [function (jsonItems){
        return new Promise(function(resolve, reject){
            if(jsonItems.type === 'file'){
                jsonItems.getFile().then(function(file){ //or promise.all?
                    resolve(file.getSize())
                })
            }
        })
    }],
    function (result, current) {
        return {
            type: current.type,
            size: jsonItems.result[0]
        }
    },
    function (err, newList) {
        if (err) {
            console.error(err)
            return;
        }
        console.log('new jsonItems : ', newList)
    })

제시된 솔루션에 덧붙여 설명하자면, 제 경우에는 제품 목록을 위해 Firebase에서 여러 데이터를 가져오려고 했습니다.제가 한 방법은 이렇습니다.

useEffect(() => {
  const fn = p => firebase.firestore().doc(`products/${p.id}`).get();
  const actions = data.occasion.products.map(fn);
  const results = Promise.all(actions);
  results.then(data => {
    const newProducts = [];
    data.forEach(p => {
      newProducts.push({ id: p.id, ...p.data() });
    });
    setProducts(newProducts);
  });
}, [data]);

언급URL : https://stackoverflow.com/questions/31413749/node-js-promise-all-and-foreach

반응형