Loop
Como criar iterações e percorrer listas no browserMate usando Iterações de Listas, variáveis de controle e condições de rota.
Como o loop funciona
O browserMate não tem um card de "loop" com ícone próprio no canvas. A técnica de loop é implícita e inteligente, sendo sempre o fluxo voltando para uma etapa anterior através de uma condição de rota. Existem duas formas de montar isso:
- Iterações de Listas (recomendada quando os dados já são uma lista). Um recurso nativo da etapa de Regra Customizada que consome um item da lista a cada execução, sem precisar escrever a lógica de índice manualmente. Veja a seção dedicada.
- Controle manual (para tudo que não é "percorrer uma lista pronta", como aguardar uma condição mudar ou paginar sem total conhecido): variáveis de controle, combinadas com uma condição de rota que decide se volta ou segue. A variável de controle pode ser criada e atualizada sem código, na seção Variáveis do Fluxo da etapa (veja Manipulação de Variáveis → Locais), ou escrita via
bm.done()e lida viabm.get()num script.
O padrão de 4 etapas
Pensando de forma independente do mecanismo, todo loop segue a mesma forma:
- Inicializar: Prepara a lista ou variáveis de controle antes da primeira iteração.
- Verificar: Decide se ainda há o que processar. Se não, sai do loop; se sim, segue.
- Processar: Etapa(s) de Execução que operam sobre o item atual.
- Avançar: Consome o item processado e volta para o passo de Verificar.
Com Iterações de Listas, os passos 2 (Verificar) e 4 (Avançar) colapsam numa única etapa: a mesma etapa de Regra Customizada consome o item da lista e decide se volta, através da sua própria condição de rota. No controle manual, os quatro passos continuam separados, e o passo 2 nem precisa ser uma etapa de Decisão dedicada, embora normalmente seja mais claro assim. A seção seguinte mostra a forma nativa; Loop sobre uma lista mais abaixo mostra a construção manual completa.
Iterações de Listas: consumindo a lista automaticamente
Toda etapa de 🔢 Regra Customizada tem uma seção Iterações de Listas, logo abaixo de Variáveis do Fluxo no painel, independente de ter ou não código customizado preenchido. A lista a percorrer pode vir de uma Coleção, de uma resposta de API, de uma variável global do tipo Lista, de uma variável local do tipo Lista, criada em Variáveis do Fluxo, ou de uma variável gravada por script (bm.done, globalData.set), desta etapa ou de outra: o seletor mostra as listas com o selo [ ] e as de script sem ele, porque o tipo delas vem da execução. A iteração roda depois das variáveis e dos scripts da mesma etapa, e o Timer de Espera da etapa, se houver, roda por último, depois da iteração. No exemplo a seguir, "Insere Registros no ERP" processa uma empresa por vez a partir da variável lista EMPRESA_LIST, e a etapa seguinte, "Confere Lista Processada", decide se volta para processar a próxima empresa ou segue em frente. "Insere Registros no ERP" referencia EMPRESA_LIST normalmente no seu mapeamento, pegando o item que está na posição atual da lista:

Repare na expressão do mapeamento: {EMPRESA_LIST}[]. Colchetes vazios logo após a variável lista sempre pegam o primeiro registro do array, o mesmo item que "Confere Lista Processada" vai descartar da lista ao avançar (direção Próximo, o padrão, explicada abaixo).
É em "Confere Lista Processada" que as duas peças se encontram: a mesma etapa que avança a lista também declara a condição de rota que decide se o processo volta para "Insere Registros no ERP" ou segue adiante. iteração e roteamento juntos, numa única etapa:

O que a seção Iterações de Listas faz, tecnicamente, é o conceito de iteração: varrer a lista automaticamente, item por item, sem precisar escrever esse controle manualmente. A direção escolhida para cada variável define o sentido da varredura:
- Próximo (padrão). Varre de cima para baixo: remove e descarta o primeiro item da lista a cada execução desta etapa.
- Anterior: varre de baixo para cima: remove o último item, processando a lista em ordem inversa.
Uma mesma etapa aceita mais de uma variável lista ao mesmo tempo, cada uma com sua própria direção, útil quando várias listas andam em paralelo, item a item (por exemplo, as colunas de uma Coleção: empresa, CNPJ, serviço e UF avançando juntos a cada iteração):

Isso substitui a necessidade de escrever bm.get() / bm.done() só para avançar um índice: a própria plataforma encurta a lista uma posição a cada vez que a etapa roda. O que sobra para você configurar é a condição de rota da mesma etapa, decidindo se ainda há itens (loop continua) ou não (segue em frente):
Regra 1:
Condição: {EMPRESA_LIST}.length > 0
Ir para: Insere Registros no ERP // volta para reprocessar o próximo item
// sem regra que bata (lista vazia) → segue para a próxima etapa da sequência
A variável lista entra na condição como lista: .length, [0] e .includes() funcionam direto sobre ela, e {EMPRESA_LIST} > 0 tem o mesmo efeito de {EMPRESA_LIST}.length > 0. Detalhes das operações com lista: Lógica de Rotas → Arrays e listas.
Loop sobre uma lista (construção manual)
Quando não usar Iterações de Listas, por exemplo se quiser lógica própria a cada avanço, o mesmo resultado é construído manualmente, passo a passo:
Os exemplos abaixo usam Node.js, mas o mesmo padrão vale para Python. bm.get(), bm.done() e bm.bmLog() existem igualmente nas duas linguagens (veja Código Inline → API de contexto do processo). A Etapa 1 abaixo tem sua versão em Python logo em seguida, como referência de tradução. bm.get() devolve a lista como lista (array no Node.js, list no Python), e o número gravado pelo bm.done() como número.
const lista = bm.get('{lista_nfs}', []);
const total = lista.length;
bm.done('init', {
'{loop_index}': 0,
'{loop_total}': total,
'{item_atual}': lista[0] || '',
'{tem_mais}': total > 0 ? 'sim' : 'nao'
});
lista = bm.get('{lista_nfs}', [])
total = len(lista)
bm.done('init', {
'{loop_index}': 0,
'{loop_total}': total,
'{item_atual}': lista[0] if total > 0 else '',
'{tem_mais}': 'sim' if total > 0 else 'nao'
})
Rota 1:
Condição: {tem_mais} == 'nao'
Ir para: Finalizar Processo
Rota 2:
Condição: true
Ir para: Processar Item
// Use {item_atual} em qualquer campo de texto desta etapa
Navegar para: https://sistema.com/nf/{item_atual}
(... outras ações sobre o item ...)
const lista = bm.get('{lista_nfs}', []);
const idx = bm.get('{loop_index}') + 1;
bm.done('avancou', {
'{loop_index}': idx,
'{item_atual}': lista[idx] || '',
'{tem_mais}': idx < lista.length ? 'sim' : 'nao'
});
lista = bm.get('{lista_nfs}', [])
idx = bm.get('{loop_index}') + 1
bm.done('avancou', {
'{loop_index}': idx,
'{item_atual}': lista[idx] if idx < len(lista) else '',
'{tem_mais}': 'sim' if idx < len(lista) else 'nao'
})
Loop while (aguardar condição)
Quando não há uma lista fixa. O loop deve continuar até que uma condição externa seja satisfeita, como um elemento aparecer na página ou um status mudar:
// Etapa: Inicializar Espera
bm.done('init', {
'{aguardando}': 'sim',
'{tentativas}': 0
});
// Etapa: Verificar Status (Decisão 🔷, ou a mesma condição na etapa anterior/seguinte)
// Rota 1: {status_atual} == 'concluido' → Prosseguir
// Rota 2: Number({tentativas}) >= 10 → Timeout
// Rota 3: true → Aguardar e Tentar
// Etapa: Aguardar e Tentar (Regra Customizada) → Ir para "Verificar Status"
const t = Number(bm.get('{tentativas}')) + 1;
bm.done('aguardou', { '{tentativas}': t });
Para um intervalo entre uma consulta e outra só nesta etapa, sem código, use o Timer de Espera: na etapa "Aguardar e Tentar", configure alguns segundos (5, por exemplo). A espera roda depois do script da etapa, então cada volta do loop aguarda antes de a rota levar de novo a "Verificar Status". Se o intervalo precisa depender de uma condição, escreva a pausa no script, como em Timers → Aguardar em scripts.
Paginação de portal
Para percorrer múltiplas páginas de um sistema (lista paginada):
// Etapa: Inicializar Paginação
bm.done('init', {
'{pagina_atual}': 1,
'{tem_proxima}': 'sim'
});
// Etapa: Verificar Próxima Página (Decisão 🔷, ou a mesma condição na etapa anterior/seguinte)
// Rota 1: {tem_proxima} == 'nao' → Finalizar
// Rota 2: true → Navegar Página
// Etapa: Navegar Página
// URL: https://portal.com/lista?page={pagina_atual}
// Etapa: Extrair Dados da Página
// Mapeamento captura dados e verifica botão "Próxima"
// {tem_btn_proxima} = 'sim' ou 'nao'
// Etapa: Avançar Página (Regra Customizada) → Ir para "Verificar Próxima Página"
const paginaAtual = Number(bm.get('{pagina_atual}')) + 1;
bm.done('avancou', {
'{pagina_atual}': paginaAtual,
'{tem_proxima}': bm.get('{tem_btn_proxima}', 'nao')
});
Cuidados e limites
número de itens × ações por iteração.
- Loop infinito: Sempre inclua uma rota de saída por contagem de tentativas ou flag de término. Um loop sem saída vai consumir todas as ações disponíveis.
- Tipos:
bm.get()devolve o valor no tipo em que ele foi gravado. Número, lista e objeto vão direto nobm.done()e voltam como número, lista e objeto; uma variável declarada como Número ou Moeda chega como número. Texto capturado da tela chega como texto: para fazer conta com ele, converta comNumber()(int()oufloat()no Python). Detalhes: Como o tipo é aplicado. - Iterações de Listas só avança se a etapa rodar: o item só é removido da lista quando a etapa de Regra Customizada configurada realmente executa. Se ela falhar (erro não tratado) e o contorno de falha desviar o fluxo para fora do loop, a lista fica do jeito que estava. Nada é descartado.
