2016-10-27 7 views
0

私は約束をいくつか持っており、順番にそれらを実行したいが、条件付きで実行したい。例えば、私は次の約束ブルーバード約束のシリーズ制御フロー

を持っている:私は何をしたいか

getItems()

getItemsSource()

getItemsAlternativeSource()

を最初getItems()を試してみてくださいです。これが空の値で解決された場合、またはエラーが発生した場合はそのエラーをログに記録したいですが、上記と同じようにgetItemsSource()を試してください。その場合はエラーを記録し、getItemsAlternativeSource()を試してください。

私はこれを条件付きで、それぞれthen()またはcatch()で行うことができますが、少し冗長であるようです。この種の制御フローを処理するより良い方法はありますか?

ありがとうございました!

答えて

1

あなたはcatchハンドラの戻り値として空の値を使用することができます。

getItems().catch(function(err) { 
    console.warn(err); 
    return null; // <== 
}).then(function(items) { 
    if (items) return items; 
    else return getItemsSource().catch(function(err) { 
     console.warn(err); 
     return null; // <== 
    }).then(function(sourceitems) { 
     if (items) return items; 
     else return getItemsAlternativeSource().catch(function(err) { 
      console.warn(err); 
      throw new Error("items couldn't be fetched normally, from source, or from alternative source"); 
     }); 
    }); 
}); 

あなたは絶対に重複を避けたい場合は、この抽象度の高いアプローチを使用することができます。

var tryAll = [getItems, getItemsSource, getItemsAlternativeSource].reduceRight(function(nextAlternative, fetch) { 
    return function() { 
     return fetch().then(function(items) { 
      if (items) return items; 
      else return nextAlternative(); // now we can even call it in two locations 
     }, function(err) { 
      console.warn(err); 
      return nextAlternative(); // without having to resort to catch-then 
     }); 
    }; 
}, function last() { 
    throw new Error("items couldn't be fetched normally, from source, or from alternative source"); 
}); 
tryAll(); 
1

いくつかのデータが返されるまで配列の各関数を呼び出す関数の配列をとる関数を作成することをお勧めします。

function getFirstData(array) { 
    var index = 0; 
    function next() { 
     if (index < array.length) { 
      return array[index++]().then(function(data) { 
       // if we got an answer, return it as the resolve value 
       if (data) return data; 
       // otherwise, reject so we go to the next one 
       return Promise.reject(null); 
      }).catch(function(err) { 
       if (err) console.err(err); 
       return next(); 
      }); 
     } else { 
      // got to the end of the array without a value 
      throw new Error("No data found"); 
     } 
    } 
    return Promise.resolve().then(next); 
} 

var fns = [getItem, getItemsSource, getItemsAlternativeSource]; 

getFirstData(fns).then(function(data) { 
    // got data here 
}).catch(function(err) { 
    // no data found here 
}); 

あなたは関数は、引数を持つようにしたい場合は、配列にそれらを置く前に、関数に引数を.bind()することができます。


そして、ここで配列を横断する.reduce()を使用して、異なる実装です:

function getFirstData(array) { 
    return array.reduce(function(p, fn) { 
     return p.then(function(priorData) { 
      // if we already got some data, then just return it 
      // don't execute any more functions 
      if (priorData) return priorData; 
      return fn().catch(function(err) { 
       console.log(err); 
       return null; 
      }); 
     }); 
    }, Promise.resolve()).then(function(data) { 
     if (!data) { 
      throw new Error("No data found"); 
     }   
    }); 
} 
関連する問題