"Continue" em cursor.forEach ()


280

Estou criando um aplicativo usando meteor.js e MongoDB e tenho uma pergunta sobre cursor.forEach (). Desejo verificar algumas condições no início de cada iteração forEach e, em seguida, pular o elemento, se não for necessário executar a operação para economizar tempo.

Aqui está o meu código:

// Fetch all objects in SomeElements collection
var elementsCollection = SomeElements.find();
elementsCollection.forEach(function(element){
  if (element.shouldBeProcessed == false){
    // Here I would like to continue to the next element if this one 
    // doesn't have to be processed
  }else{
    // This part should be avoided if not neccessary
    doSomeLengthyOperation();
  }
});

Eu sei que eu poderia transformar o cursor em array usando cursor.find (). Fetch () e, em seguida, use o loop for regular para iterar sobre os elementos e usar continue e quebre normalmente, mas estou interessado se houver algo semelhante a ser usado no forEach ( )

Respostas:


562

Cada iteração do forEach()chamará a função que você forneceu. Para interromper o processamento adicional em qualquer iteração (e continuar com o próximo item), basta returnpartir da função no ponto apropriado:

elementsCollection.forEach(function(element){
  if (!element.shouldBeProcessed)
    return; // stop processing this iteration

  // This part will be avoided if not neccessary
  doSomeLengthyOperation();
});

18
Você sabe talvez o que poderia ser o "intervalo", se continuar é apenas "retornar".
usar o seguinte comando

5
Eu não uso o MongoDB, por isso não li sua documentação, mas é possível que return false;seja o equivalente a break;(como é para um .each()loop jQuery ). É claro que quem implementado MongoDB de .forEach()ter tido outras idéias ...
nnnnnn

10
@ Drag0 Você pode usar .some () como um substituto para .forEach (), que permite retornar false para interromper o loop.
19415 Andrew

6
@Andrew Você pode usar some, apenas esteja ciente de que está usando indevidamente (ou usando criativamente) uma função destinada a dizer se algum dos elementos corresponde à condição. Mais ou menos como quando vejo as pessoas usam mape ignorar o resultado (que deveria ter usado forEach)É semântica, as pessoas vão ter que olhar duas vezes para saber por que você está usando. someQuando você realmente não se preocupam com o resultado
Juan Mendes

1
@ Andrew ótima dica, no entanto, é return trueque vai quebrar a algum laço
daviestar

11

Na minha opinião, a melhor abordagem para conseguir isso usando o filter método pois não faz sentido retornar em um forEachbloco; para um exemplo no seu snippet:

// Fetch all objects in SomeElements collection
var elementsCollection = SomeElements.find();
elementsCollection
.filter(function(element) {
  return element.shouldBeProcessed;
})
.forEach(function(element){
  doSomeLengthyOperation();
});

Isso limitará o seu elementsCollectione manterá apenas os filtredelementos que devem ser processados.


3
Isso iterar os elementos encontrados duas vezes, uma no filtere o segundo no forEachse uma grande coleção, será muito ineficiente
Dementic

1
Você está certo, mas não acho que seja um grande problema, pois a complexidade do tempo disso seria a O(2n)que pode ser considerada O(n).
precisa saber é o seguinte

2
Considerando que o SO está sendo usado por outras pessoas, não apenas o OP, postando uma solução apenas com a finalidade de publicá-la, está criando mais mal do que bem. A resposta acima faz isso em uma iteração e é a rightmaneira de fazê-lo.
Dementic

Observe que a coleção do OP não é uma matriz, é um objeto de cursor do Mongo DB, que não parece ter um .filter()método, portanto, você deve chamar o .toArray()método antes de poder.filter()
nnnnnn

7

Aqui está uma solução usando for ofe em continuevez de forEach:


let elementsCollection = SomeElements.find();

for (let el of elementsCollection) {

    // continue will exit out of the current 
    // iteration and continue on to the next
    if (!el.shouldBeProcessed){
        continue;
    }

    doSomeLengthyOperation();

});

Isso pode ser um pouco mais útil se você precisar usar funções assíncronas dentro de seu loop que não funcionem dentro forEach. Por exemplo:


(async fuction(){

for (let el of elementsCollection) {

    if (!el.shouldBeProcessed){
        continue;
    }

    let res;

    try {
        res = await doSomeLengthyAsyncOperation();
    } catch (err) {
        return Promise.reject(err)
    }

});

})()

2

Fazendo uso da avaliação de curto-circuito JavaScripts . Se el.shouldBeProcessedretornar verdadeiro,doSomeLengthyOperation

elementsCollection.forEach( el => 
  el.shouldBeProcessed && doSomeLengthyOperation()
);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.