等待对象

时间:2020-05-26 03:47:34

标签: javascript html node.js web

我正在尝试在JS中编写逻辑以在调用序列中突然停止函数执行(无需进一步执行)。检查以下代码。为什么在第二通电话后仍不停止?

function myprom (value) {
  return new Promise (function (resolve, reject) {
    resolve("I Promise " + value)
  })
}

function myfunc (value) {
  console.log("Starting in " + value)
}

function terminate() {
  setTimeout(() => console.log("Edning"), 1)
}

function dummy() {
  console.log("I am not supposed to print anything")
}

async function call() {
  await myprom("to end without showing next line")
    .then(result => {
      myfunc(1)                       // Call # 1
      console.log(result)             // Call # 2
      terminate()                     // Call # 3
      dummy(1)                        // Call # 4
      terminate()                     // Call # 5
    })
    .catch(err => {
      console.log(err)
    })
}

call()

下面是我的代码的实际输出。

Starting in 1
I Promise to end without showing next line
I am not supposed to print anything
Ending
Ending

期望的是,

Starting in 1
I Promise to end without showing next line
Ending

通常。如何突然停止.then对象内的js执行?

3 个答案:

答案 0 :(得分:0)

您可以使用return代替调用终止。那可以解决您的目的。

答案 1 :(得分:0)

当您致电terminate()这是

function terminate() {
  setTimeout(() => console.log("Edning"), 1)
}

setTimeout()将其回调推至事件循环的未来循环,而在事件循环的当前循环中的其他所有循环都将在此循环之前运行。只有当当前代码链完成并且控制权返回事件循环时,setTimeout()才有机会运行其回调。

因此,这是代码中发生的事情的顺序:

  1. call()被执行。
  2. myprom()被执行。这立即解决了其诺言,因此它将在控制权返回事件循环后立即安排其.then()处理程序运行。
  3. .then().catch()运行。他们目前所做的只是注册一些回调,以便在Promise准备执行它们时稍后再调用。
  4. 您的异步函数返回,控制权返回事件循环。
  5. 已经解决的promise在事件循环中排在第一位,因此它可以控制并执行其.then()处理程序。
  6. myfunc(1)运行并输出Starting in 1
  7. console.log(result)运行并输出I Promise to end without showing next line
  8. terminate()运行,从现在开始将计时器设置为1毫秒。该函数返回,并且计时器已安排在经过1毫秒后在事件循环的将来时间运行。
  9. dummy(1)被调用,并输出I am not supposed to print anything
  10. terminate()被再次调用,并再次安排另一个计时器在事件循环的将来时间间隔内以1ms运行。
  11. await处理承诺并解决async函数call()返回的承诺。 await在这里没有任何用处,也没有人在听call()返回的承诺。
  12. 控制权返回到事件循环。
  13. 您第一次调用terminate()设置的第一个计时器开始运行并输出。这样会将控制权返回到事件循环。
  14. 通过第二次调用terminate()设置的第二个计时器开始运行并投入运行。这样会将控制权返回到事件循环,并且与此代码相关的所有操作都已完成。

通常。如何突然停止.then对象内的js执行?

如果您要问的是如何跳过连续调用的其他函数,则通常会使用条件从return回调中提早分支.then()。例如,您可以这样做:

async function call() {
  await myprom("to end without showing next line")
    .then(result => {
      myfunc(1)                       // Call # 1
      console.log(result)             // Call # 2
      if (result === "I Promise to end without showing next line") {
          // skip the rest of the code in this callback
          return;
      }
      terminate()                     // Call # 3
      dummy(1)                        // Call # 4
      terminate()                     // Call # 5
    })
    .catch(err => {
      console.log(err)
    })
}

call()

由于您处于.then()处理程序中,因此您也可以使用throw someError,这将突然停止.then()处理程序,就像抛出任何异常会中止当前函数的执行一样。因为这是在.then()处理程序中,所以该异常将立即被捕获,然后将执行.catch()处理程序并将其引发的异常传递给它。通常不会将其用于正常的执行路径,因为这通常表示某些错误情况。正常的执行路径更有可能在本地捕获条件,并使用分支或if/else逻辑或类似的逻辑来决定函数中的哪些代码下一步执行。


请注意,如果您已经启动了一些计时器,则为了防止它们触发,您必须保存timerID返回的setTimeout()并在该{{ 1}}取消计时器。

如果您真的想突然停止以停止整个过程,那么在node.js中,您也可以调用clearTimeout()


目前还不清楚为什么您认为timerID的输出和对process.exit()的第二次调用不会显示在输出中?您打电话给dummy(1)terminate()函数中的任何内容都不会导致Javascript跳过dummy(1)处理程序中的其余代码。因此,它继续并同时执行terminate()和第二个.then(),因此您会看到两者的输出。

答案 2 :(得分:0)

函数terminate不会停止执行该函数,而是将其安排在以后至少1秒钟的超时时间内运行。因此,该函数应改为称为delay。我添加了基于Promise的实现:

function delay(time = 1) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('Ending');
      resolve();
    }, time);
  })
}

可以等待一个返回标量值的函数。因此,无需使用Promise构造函数包装myProm。当然,假设myprom是一个真正的异步操作,而不是一个返回字符串的函数。

function myprom (value) {
  return `I Promise ${value}`;
}

使用异步函数时,不需要使用.then.catch进行回调。

async function call() {
  try {
    const result = await myprom("to end without showing next line")
    console.log(result)
    myfunc(1)
  } catch (e) {
    console.error(e);
  }
}

具有更改的现有代码段如下所示:

// scalar values can be resolved too
function myprom (value) {
  return `I Promise ${value}`;
}

function myfunc (value) {
  console.log("Starting in " + value)
}

function delay(time = 1) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('Ending');
      resolve();
    }, time);
  })
}


function dummy() {
  console.log("I am not supposed to print anything")
}

async function call() {
  try {
    const result = await myprom("to end without showing next line")
    console.log(result)
    myfunc(1)
    await delay();
    dummy(1);
    await delay();
  } catch (e) {
    console.error(e);
  }
  
  return undefined;
}

call();

但是,正如所解释的那样,这不会停止执行流程:

  • myprom运行

  • result已打印

  • myFunc执行

  • 1秒的延迟后,将显示一条消息Ending(因为事件循环没有被许多异步操作阻止)

  • 假人执行

  • 在1秒钟的延迟后,将显示一条消息Ending

  • 该函数返回一个Promise,其值解析为undefined。

当需要终止执行函数时,可以使用delay来代替return

function myprom(value) {
  return `I Promise ${value}`;
}

function myfunc(value) {
  console.log("Starting in " + value)
}


async function call() {
  try {
    const result = await myprom("to end without showing next line")
    console.log(result)
    myfunc(1);
    return
  } catch (e) {
    console.error(e);
  }
}

call();