如何在JavaScript中的异步Promise中使用同步?

时间:2019-02-03 19:25:51

标签: javascript asynchronous promise synchronization

当我运行以下代码时:

b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  b(attempt + 1).then(() => {
    console.log("Finished attempt:", attempt);
  });
};
b(0);

输出为:

Starting attempt: 0
Starting attempt: 1
Starting attempt: 2
Starting attempt: 3
Starting attempt: 4
Finished attempt: 4
Finished attempt: 3
Finished attempt: 2
Finished attempt: 1
Finished attempt: 0

但是,我想在每次递归调用之前调用另一个诺言a,如下所示:

a = Promise.resolve();
b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  a.then(() => {
    b(attempt + 1);
  }).then(() => {
    console.log("Finished attempt:", attempt);
  });
};
b(0);

现在输出为:

Starting attempt: 0
Starting attempt: 1
Starting attempt: 2
Finished attempt: 0
Starting attempt: 3
Finished attempt: 1
Starting attempt: 4
Finished attempt: 2
Finished attempt: 3
Finished attempt: 4

如何修改第二个代码块以确保输出与第一个代码块相同?

3 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题,则问题是由嵌套的promise和对异步函数(即b(attempt + 1)的调用)引起的,而这并不阻止封闭函数的执行。反过来,这会产生无序且意外的日志记录结果。

考虑通过b()return的承诺来修订对b(attempt + 1);的调用,以确保在console.log("Finished attempt:", attempt)完成后执行以下日志:b()完成:

const a = Promise.resolve();
const b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  
  await a.then(() => {
  
    /* 
    Return the project of b() here, has similar effect
    to that of await keyword
    */
    return b(attempt + 1); 
  }).then(() => {
    console.log("Finished attempt:", attempt);
  });
};

b(0);

答案 1 :(得分:1)

您通过不返回内部承诺a.then(() => {b(attempt + 1);})破坏了承诺链。添加return语句应该会有所帮助。

我也建议不要将async/await语法与.then和回调一起使用。

以下代码看起来更“同步”,并且可以解决问题。

const a = Promise.resolve();
const b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  
  await a
  
  await b(attempt + 1)
  
  console.log(`Finished attempt: ${attempt}`)
};

b(0);

答案 2 :(得分:1)

您忘记了return您正在创建的承诺链:

const b = attempt => {
  if (attempt == 5) {
    return Promise.resolve();
  }
  console.log("Starting attempt:", attempt);
  const a = Promise.resolve();
  return a.then(() => {
//^^^^^^
    return b(attempt + 1);
//  ^^^^^^
  }).then(() => {
    console.log("Finished attempt:", attempt);
  });
};
b(0).then(() => {
  console.log("done");
});

只有使用那些return,函数的调用者才能等待promise。您的第一个片段有相同的问题。如果您省略了async关键字,那就更加明显了,这样很显然b()并没有返回承诺。

如果您想使用async / await,则代码应如下所示:

const b = async attempt => {
  if (attempt == 5) {
    return;
  }
  console.log("Starting attempt:", attempt);
  await Promise.resolve();
//^^^^^
  await b(attempt + 1);
//^^^^^
  console.log("Finished attempt:", attempt);
};
b(0).then(() => {
  console.log("done");
});