Async: quebrar a corrente da cachoeira sem lançar um erro

Criado em 15 fev. 2011  ·  8Comentários  ·  Fonte: caolan/async

Disseram-me que preciso refatorar meu código que está usando a cascata assíncrona. Usei-o principalmente porque tinha várias funções encadeadas que estavam indo muito fundo e queria reutilizar uma função, etc. Há uma condição em um ponto abaixo da cadeia que não é estritamente uma condição de erro, mas eu não quero passar o resto da cadeia em cascata, porque é inútil - digamos, por exemplo, fiz uma consulta e não há resultados, e isso não é um erro, não quero propagar todo o caminho sem resultados. Se eu estivesse fazendo isso sem assíncrono, acho que teria um retorno de chamada "final" e que poderia ser chamado para quebrar a cadeia sem gerar um erro explicitamente. Esta funcionalidade não parece estar presente em cascata. Existe uma maneira de fazer isso de forma limpa? A única maneira que vejo de fazer isso é lançar um erro especial e, em seguida, lidar com isso no retorno de chamada final para retornar um erro não.

Comentários muito úteis

Pessoalmente, acho que preciso de uma funcionalidade como essa e acho que ela deveria ser adicionada à biblioteca central.

Aqui está a minha solução alternativa auxiliar, se alguém estiver interessado ...

exports.breakWaterfall = function(tasks, callback){
    async.waterfall(tasks, function(){
        if(arguments[0] === 'break'){
            arguments[0] = null;
        }
        callback.apply(null, arguments);
    });
}

Se você precisar ir para a última função em uma tarefa, basta chamar o callback assim: done('break', other, arguments); .

O auxiliar apenas detecta 'break' e altera os argumentos para que o resto do código não pareça um erro.

Todos 8 comentários

Oi,

você provavelmente já resolveu seu problema, a propósito, esta é a minha abordagem:

var flow = [
    async.apply(...),
    // ...
];

async.waterfall(flow, function (err) {
    if (err === 'ok') return;
    // handle error
});

Quando uma função chama um retorno de chamada com err = 'ok' , o retorno de chamada final da cascata o intercepta.

Eu tenho um problema semelhante e estou adicionando um invólucro de retorno de chamada (que eu poderia evitar) apenas para verificar se é um erro ou não para cada cachoeira que uso. Não é tão limpo quando há mais de uma cachoeira.
A própria função de retorno de chamada pode ter outra propriedade chamada 'final', que as pessoas poderiam chamar para ir até o fim?
Algo como

function search (cond, callback) {
  async.waterfall([function (cb) {
      db.get(cond, cb);
    },
    function (res, cb) {
      if (!res || !res.length)
        return cb.final();
      //do something useful
    }
  ], callback);
}

Eu não terei que encerrar o retorno de chamada e pode ser encadeado para o resto do programa.

@caolan, há algo que você não goste na solicitação de pull do @jnordberg ? Em caso afirmativo, há algo que eu possa fazer para que essa solicitação pull seja aceita?

@tax : na verdade, descobri que podemos pular para a função final passando 'error' = true assim:

async.waterfall ([function (callback) {
retorno de chamada (nulo); // <--- ir para o próximo fn
},
function (callback) {
retorno de chamada (verdadeiro); // <--- pular para o último fn
},
function (callback) {
retorno de chamada (nulo); // <--- este fn não será chamado
}
], ligar de volta);

@ tot2ivn obrigado pela dica!

Se você definir o erro, o resultado ficará vazio.

var async = require('async');

async.waterfall( [
  function( callback ){
    console.log('one');
    callback( null );
  },

  function( callback ){
    console.log('two');
    callback( true, 'more info' );
  },

  function( callback ){
    console.log('three');
    callback( null );
  }
], function(err, result){
  console.log( err, result );
} );

// RESULT
// one
// two
// true undefined

À luz do comentário de

Pessoalmente, acho que preciso de uma funcionalidade como essa e acho que ela deveria ser adicionada à biblioteca central.

Aqui está a minha solução alternativa auxiliar, se alguém estiver interessado ...

exports.breakWaterfall = function(tasks, callback){
    async.waterfall(tasks, function(){
        if(arguments[0] === 'break'){
            arguments[0] = null;
        }
        callback.apply(null, arguments);
    });
}

Se você precisar ir para a última função em uma tarefa, basta chamar o callback assim: done('break', other, arguments); .

O auxiliar apenas detecta 'break' e altera os argumentos para que o resto do código não pareça um erro.

Esta página foi útil?
0 / 5 - 0 avaliações