Javascript递归函数 - 在休假级

时间:2015-05-29 21:04:20

标签: javascript asynchronous recursion

在下面的程序中,当最初调用recurse(prog)时(第64行),它递归地挖掘exp(第1行)中描述的表达式prog,在这种情况下切换exp.type = A,B或C.

在递归调用的最底层(当大小写(" C"))时,我调用verySlowMan(exp.value)查找collections列表以检查是否名称为exp.value的集合是否存在。

如果是,则返回集合

如果不是,则返回新的Error

问题是verySlowMan()花时间检索一个集合。

为简单起见,我提出了一个简单的if else条件,但verySlowMan最终会发出XHR请求。所以这是不可预测的慢

问题如下

如何在递归调用中传播verySlowMan的返回值,以便在调用recurse(prog)时得到一个很好的集合列表?

目前,出于可以理解的原因,我得到[null,[null,null],null]。但我真的不知道如何解决它。

我试图从verySlowMan返回deferred.promises,但在这种情况下,我认为recurse()也应该为每个递归调用返回一个新的promise。

(1)我不确定如何正确地做到这一点

(2)我怀疑它是最好的方式

注意:progcollections中的项目数量和递归()中的案例可能会变得很长。

以下是该计划:

var prog = {
  type : "A", value : [
    { type : "B", value : "C1" },
    { type : "B", value : [
      { type : "C", value : "C2" },
      { type : "C", value : "end" }
    ]},
    { type : "B", value : "C3" }
  ]
}

var collections = [
  { name : "C1", data : ["item1", "item2", "item3"]},
  { name : "C2", data : ["item1", "item2", "item3"]}
]

function verySlowMan( collectionToFind ){

  collections.forEach(function(collection){

    if ( collection.name === collectionToFind ) {
      return collection;
    }else{
      return new Error("No Collection");
    }
  });

  return null;
}

function recurse(exp){

  switch(exp.type){
    case("A"):
      var As = [];
      exp.value.forEach( function(B){
        As.push ( recurse(B) );
      } );
      return As;
      break;

    case("B"):
      var Bs = [];
      if (typeof(exp.value) === 'string') {
        return verySlowMan( exp.value );

      } else {
        exp.value.forEach( function(C){
          Bs.push ( recurse(C) );
        } );
        return Bs;
      }
      break;

    case("C"):
      return verySlowMan( exp.value );
      break;

    default:
      throw new Error('wrong type');
  }
}

console.log( recurse(prog) ); // -> [ null, [ null, null ], null ]

1 个答案:

答案 0 :(得分:1)

以下是promises的例子。

function verySlowMan( collectionToFind ) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      for(var i = 0; i < collections.length; i++) {
        if ( collections[i].name === collectionToFind ) {
          resolve(collections[i]);
          return;
        }
      }
      reject(new Error("No Collection"));
    }, 100);
  });
}

function recurse(exp){
  function errorHandler(err) {
    if(err.message === "No Collection") return null;
    else throw err;
  };
  switch(exp.type){
    case("A"):
      return Promise.all(exp.value.map(recurse));
    case("B"):
      if (typeof(exp.value) === 'string') {
        return verySlowMan(exp.value).catch(errorHandler);
      } else {
        return Promise.all(exp.value.map(recurse));
      }
    case("C"):
      return verySlowMan( exp.value ).catch(errorHandler);

    default:
      return Promise.reject(new Error('wrong type'));
  }
}

recurse(prog).then(function(result) {
  console.log(result);
}).catch(function(err) {
  console.log(err.stack);
});