承诺不使用setTimeOut从递归函数解析

时间:2018-08-16 08:14:06

标签: javascript recursion promise async-await generator

我想在循环中延迟一段时间后执行一些代码。一旦完成所有迭代,我想做其他一些任务。这些取决于从task1获得的结果。为此,我使用生成器,async / await和promise编写了以下代码片段:

function* iter() {
 for (var i = 0; i < 10; i++) yield i
}

async function start() {
    var myIter = iter();
    var p = await cb1(myIter);
    console.log('after await');
        p.then((value) => {
        console.log('-----------here-------------');
    });
}

start();

function cb1(myIter) {
    console.log("Started : " + new Date());
    var obj;
    return new Promise((resolve, reject) => {
        setTimeout(function(){
        if(myIter.next().done === true) {
            console.log("End : " + new Date());
            resolve('done');
        }else {
            console.log("---in else---");
            cb1(myIter);
        }
    }, 3000);
    });
}

问题在于,永远不会打印p.then()中的控制台。这意味着承诺永远不会得到解决,程序会终止。迭代按预期执行,但是承诺永远无法解决。这有什么问题吗?我正在使用递归来触发iterator.next(),并且只想在最后一次迭代(即done = true时)上解决承诺。

很久以来,我一直在这个问题上挠头。感谢帮助。以下是该程序的输出。

enter image description here

3 个答案:

答案 0 :(得分:2)

几个问题:生产线

var p = await cb1(myIter);

p分配了调用cb1的结果的。除非构造的p 也解析为Promise ,否则Promise也不是Promise,这是不寻常的。因为await实际上会暂停脚本的执行,直到承诺解决为止,所以您不需要.then-您只需要在console.log函数中添加下面的start。一旦将诺言正确地链接在一起,p就会解析为'done' string ,这当然不是Promise

但是还有另一个问题:cb1返回的诺言永远都无法解决,除非在最后,您要呼叫resolve。在else中,您永远不会打电话给resolve,因此这些承诺永远永远都没有解决。要解决此问题,请更改

  } else {
    console.log("---in else---");
    cb1(myIter);
  }

  } else {
    console.log("---in else---");
    cb1(myIter).then(resolve);
  }

,以便下一个迭代的Promise解析后,当前迭代的Promise解析。

function* iter() {
  for (var i = 0; i < 3; i++) yield i
}

async function start() {
  var myIter = iter();
  var p = await cb1(myIter);
  console.log('after await');
  console.log('-----------here-------------');
}

start();

function cb1(myIter) {
  console.log("Started : " + new Date());
  var obj;
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      if (myIter.next().done === true) {
        console.log("End : " + new Date());
        resolve('done');
      } else {
        console.log("---in else---");
        cb1(myIter).then(resolve);
      }
    }, 1000);
  });
}

答案 1 :(得分:1)

还需要1个功能,然后它才能起作用:

   function* iter() {
 for (var i = 0; i < 10; i++) yield i
}

async function start() {
    var myIter = iter();
    var p = await cb1(myIter);
    console.log('after await');
    console.log("here is p:" + p.done + "," + p.value);
}

start();

function repeat(myIter,resolver,previous){
    var temp;
    if((temp = myIter.next()).done === true) {
        console.log("End : " + new Date());
        resolver(previous);
    }else {
        console.log("---in else---");
        setTimeout(function(){repeat(myIter,resolver,temp)},3000);
    }
}

function cb1(myIter) {
    console.log("Started : " + new Date());
    var obj;
    return new Promise((resolve, reject) => {
       repeat(myIter,resolve);
    });
}

还修复了p,等待将其取出,您需要获取先前的值

答案 2 :(得分:1)

有两个问题:

  1. await的结果永远不会是一个承诺; await的目的是等待承诺解决,并为您提供分辨率值。因此,您代码中的p并不是一个承诺,也不会有then方法。但是由于#2,您不会因此而出错。
  2. cb1
  3. 每次调用使用新的resolve函数创建一个新的Promise。您的最后一个setTimeout回调正在解决最后一个诺言,但是没有一个解决第一个诺言,因此您永远不会越过var p = await cb1(myIter);行。

您可能需要一个用于计时器回调的内部函数,然后通过cb1调用返回的promise进行解析。

遵循以下原则:

function* iter() {
    for (var i = 0; i < 10; i++) {
        yield i;
    }
}

async function start() {
    var myIter = iter();
    var p = await cb1(myIter);
    console.log("p = ", p);
}

start();
function cb1(myIter) {
    console.log("Started : " + new Date());
    return new Promise((resolve, reject) => {
        iteration();
        function iteration() {
            setTimeout(function() {
                if (myIter.next().done) { // `=== done` is pointless here
                    console.log("End : " + new Date());
                    resolve('done');
                } else {
                    console.log("---in else---");
                    iteration();
                }
            }, 3000);
        }
    });
}