【问题标题】:How to force an event callback to wait until async call is resolved?如何强制事件回调等到异步调用解决?
【发布时间】:2020-07-29 15:12:04
【问题描述】:

我有一个表单来监听名为onBeforeSubmit 的事件。当我提交表单时会触发此事件,但如果回调返回false,则会停止提交。

问题

我的回调涉及对 API 的异步调用。在决定是否返回 false 之前,如何强制事件等待承诺解决?目前它不会等待fetch() 解决 - 我已经尝试了async/await.then() 方法......

我尝试了什么:

尝试 1:

onBeforeSubmit: async (e) {
  const res = await fetch(url);
  // if res value fails some condition
  return false
}

尝试 2:

onBeforeSubmit: (e) {
  fetch(url).then( res => {
  // if res value fails some condition
  return false
  })
}

await 不应该强制 javascript 等到 fetch 解决后再继续下一行吗?

我还注意到,每当我输入 async 关键字时,它都会忽略 return false 语句并继续提交。是什么原因造成的?

编辑:这是第 3 方 API,所以我无法控制 onBeforeSubmit 的行为方式:(

【问题讨论】:

  • 不,async 总是返回一个承诺。要访问false,调用者需要等待承诺解决。您能否提供更多上下文并稍微修饰一下示例 - 接收 return false 值的函数是否在您的控制之下?
  • 是什么让您认为您的代码没有等待 fetch 返回的承诺解决?
  • 嗨@ggorlen,感谢您的回复 - 不幸的是,它来自第 3 方 API,所以我无法控制它。我希望找到一种方法让它接受承诺。
  • @NickParsons 目前,即使在.then 中使用return 语句,表单也会被提交。据我了解,包装函数仅在.then 内返回。不过好像我理解错了。
  • 这可能是因为调用者将 promise 视为真的:console.log(!!new Promise(res => res)) 打印为 true。

标签: javascript asynchronous promise async-await dom-events


【解决方案1】:

您有一个期望同步返回值的事件处理程序,但您试图在该回调中运行异步操作。这在 Javascript 中是行不通的。

当您运行异步函数时,您的回调函数会立即返回,并且异步函数会在其自己的回调中结束。如果你标记回调async,那只是意味着它会立即返回一个承诺。由于onBeforeSubmit 事件处理程序期望返回一个布尔值,而不是一个承诺,所以它不能正常工作。

Javascript 没有办法让这个回调“等待”,所以它可以同步返回一个布尔值。

解决此问题的常用方法是始终返回false,因此不会自动提交表单。然后,运行您的异步操作,如果成功,则您从该异步完成回调中手动提交表单(无需进一步验证)。

【讨论】:

  • 感谢您的回答,我怀疑是这种情况。感谢您的解决方法建议,这似乎是可行的。我会尝试并回来查看!
  • @micronyks - 鉴于 OP 正在使用来自期望同步返回布尔值的框架的回调,这种解释有什么问题?看起来更像是您不了解这里的实际问题。无法从 Javascript 中的异步操作中获取同步返回的布尔值。
  • 你不知道async await的用法和它是如何工作的。先学吧。您的第一句话本身就是错误的.....
  • @micronyks - 您缺少基本概念,即 OP 正在使用的框架中的某些代码期望从函数返回 SYNCHRONOUS 布尔值。这就是OP所需要的。没有多少await 会提供这样的服务。另外,请注意 OP 添加到他们的问题中的编辑 This is a 3rd party API, so I can't control how onBeforeSubmit behaves
  • @micronyks - 这就是您误解 await 并误解 OP 工作的约束的地方。它不会使过程同步。它不允许您同步返回布尔值(这是 OP 使用的 API 所期望的)。 await 暂停一个函数的内部执行,然后该函数在该点立即返回一个承诺(不是布尔值)。我不会再和你争论这个了。
【解决方案2】:

我建议,使用event.preventDefault() 停止提交表单,然后发出fetch 请求,如果响应值为false,则首先没有提交表单,否则删除表单的事件监听器onsubmit 然后你添加一个新的事件监听器来提交表单

这是您的代码应该是什么样子的示例

var submitform=function sbmform(e){
  e.preventDefault()
  fetchvalue()
}
const form = document.getElementById('myform')
form.addEventListener('submit',submitform,false)

async function fetchvalue(){
  const res = await fetch(url);
 if (res=="to conditon"){  // set your condfiton
       return false
  }
 else{
  form.removeEventListener('submit', submitform, false);
  form.submit()
 }
}

【讨论】:

  • 请注意fetchvalue() 应该是async。还有一个相对较新的 .requestSubmit() 方法,它将执行表单验证(因为 .submit() 不这样做),如果他们可以支持它,这可能对 OP 有用
  • @NickParsons ops,感谢您指出这一点,我不知道 .requestSubmit() 在这种情况下使用它似乎更好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
相关资源
最近更新 更多