javascript 使用async await和.then

c9qzyr3d  于 2023-03-21  发布在  Java
关注(0)|答案(8)|浏览(318)

同时使用async/await.then().catch()是否有任何危害,例如:

async apiCall(params) {
    var results = await this.anotherCall()
      .then(results => {
        //do any results transformations
        return results;
      })
      .catch(error => {
        //handle any errors here
      });
    return results;
  }
iezvtpos

iezvtpos1#

我总是使用async/await.catch()而不是使用async/awaittry/catch来使代码紧凑。

async function asyncTask() {
  throw new Error('network')
}
async function main() {
  const result = await asyncTask().catch(error => console.error(error));
  console.log('result:', result)
}

main();

如果希望在发生错误时获取回退值,可以忽略错误并在.catch()方法中返回一个值

async function asyncTask() {
  throw new Error('network')
}
async function main() {
  const result = await asyncTask().catch(_ => 'fallback value');
  console.log('result:', result)
}

main();
66bbxpm5

66bbxpm52#

我不想把事情弄得一团糟,但我想指出的是,使用await沿着then链意味着:

const x = await someAsyncFn().then(() => doSomeLogging());

x的值被赋值为 * .then的 * 返回值(即undefined,如果doSomeLogging是空的),这对我来说并不是非常直观的。

ie3xauqp

ie3xauqp3#

async函数可以包含一个await表达式,该表达式暂停async函数的执行并等待传递的Promise的解析,然后恢复async函数的执行并返回解析的值。
从下面的例子中你可以看到,你可以使用两种方法来处理await result和errors,关键字await使JavaScript等待,直到promise解决并返回其结果(一个你从resolved promise中得到的结果)。因此,没有伤害(我不完全理解你在这里所说的伤害)。

function returnpromise(val) {
  return new Promise((resolve, reject) => {
    if (val > 5) {
      resolve("resolved"); // fulfilled
    } else {
      reject("rejected"); // rejected
    }
  });
}

//This is how you handle errors in await
async function apicall() {
  try {
    console.log(await returnpromise(5))
  } catch (error) {
    console.log(error)
  }
}

async function apicall2() {
  let data = await returnpromise(2).catch((error) => {
    console.log(error)
  })
}

apicall2();
apicall();

有关更多参考,请查看-MDN DOCS

mzmfm0qo

mzmfm0qo4#

我不认为混合使用async/await + then是一个好主意。特别是当你专注于async函数的res时,混合使用会带来一些风险,会悄悄地扭曲你的res。
示例:

const res = await fetchData().then(()=>{return "something else"}).catch((err)=>{});

console.log(res); // not expected res data but something else

所以,混合使用是危险的,顺便说一句,它会伤害阅读代码。

qvsjd97n

qvsjd97n5#

如果你使用Async/await,你不需要链接.then(),只需要将resolve()返回的结果存储在一个变量中(在示例中为response),但是如果你想处理错误,你必须尝试/捕获你的代码:

async function f() {

  try {
    let response = await fetch('http://no-such-url');
  } catch(err) {
    alert(err); // TypeError: failed to fetch
  }
}

在Promise中用途:
throw new Error("oops!");
或者
Promise.reject(new Error("Whoops!"));

e5nszbig

e5nszbig6#

没有害处,但代码更多,更难阅读,你可以这样做:

async apiCall(params) {
 try{
   var results = await this.anotherCall()
    return results;
 } catch(err){
   //do something with the error
 }
}

虽然我不知道你在这里想做什么,但是在try块中返回results只意味着函数在错误情况下可能返回undefined。
同样重要的是要记住,异步函数总是返回一个promise,所以要使用apiCall函数,你有两种方法:

// 1- using .then to access the returned value
apiCall().then(results => {
   if(results){
      //doing something with the results
  }
})

// 2- awaiting the function inside another async function
async anotherFunction(){
  const results = await apiCall();
  if(results){
      //doing something with the results
  }
}

使用if(results)可以确保处理的不是undefined

cu6pst1q

cu6pst1q7#

我认为这篇文章中有一些关于“伤害”的混淆。如果你把伤害定义为(仅仅)“OP的代码是否正确运行?”,那么它就不是有害的。
然而,如果你把伤害定义为“this is a difficult-to-read, error-prone antipattern that tends to cause bugs,而且从来没有真正必要诉诸”,那么它确实是有害的。
在Stack Overflow上有无数的问题,OP混合了.thenawait,最后出现了一个bug。我选择了一些包含在本文底部。
作为一个简单的经验法则,永远不要在一个函数中合并awaitthen。最好的情况是,它比使用其中一个更难阅读,最坏的情况是,它隐藏了一个bug,通常与错误处理有关。
一般来说,async/await优于.then。如果您很难确定何时使用哪个,请更进一步,完全避免使用.then.catch
也就是说,我喜欢偶尔使用.then,当涉及错误处理时,它可以不那么冗长,并且不需要access state on an object that can't be readily passed through the chain

fetch("https://www.example.com")
  .then(response => {
     if (!response.ok) {
       throw Error(response.statusText);
     }

     return response.json();
   )
  .then(data => console.log(data))
  .catch(err => console.error(err));

对我来说,这比:

(async () => {
  try {
    const response = await fetch("https://www.example.com");
  
    if (!response.ok) {
      throw Error(response.statusText);
    }

    console.log(response.json());
  }
  catch (err) {
    console.error(err);
  }
})();

使用顶层await,底层代码变得更吸引人,尽管在实践中,您通常编写的是函数。
我同意this answer给出的一个例外,即偶尔在await链上使用.catch,以避免出现有点难看的try/catch
下面是一个例子,说明这可能是有用的:

const fs = require("node:fs/promises");

const exists = async pathName =>
  !!(await fs.stat(pathName).catch(() => false));

可能优于async/await/try/catch版本:

const exists = async pathName => {
  try {
    await fs.stat(pathName);
    return true;
  }
  catch (err) {
    return false;
  }
};

...或者可能不取决于你是否觉得catch版本太聪明了。
请注意,这里没有.thenawait的混合,只有.catch而不是try/except。这里的一般启发式是“更平坦更好”(.catchtry/catch更平坦,await.then更平坦)。

  • (是的,这个例子有些做作,因为对于这个特定的任务,有一种非常简洁的方式可以单独使用.then/.catch,但是这种模式可能会不时出现在其他上下文中)*

正如所承诺的,这里有一小部分我看到的混合使用awaitthen(以及其他一些promise反模式)所导致的混淆的例子:

相关的threads:

qybjjes1

qybjjes18#

只是为了补充这组答案,我总是使用await和then来使代码更具可读性,就像这样(aws示例):
几年前我发现了这个代码片段(功能),可能在堆栈的某个地方,我只是不记得在哪里!

async function myFunction(){
  var params = ....
  
  // either err will be null and data will have a value or if an exception was caused then data will be null and err will contain the information from the catch.
  let [err, result] = await to(route53.changeResourceRecordSets(params).promise())

  if(err){

    // handle the error
  }

  // carry on
}

to(promise){ // dunno why I called "to" call it anything you like.
  return promise.then((data) => {
  return [null, data]
 }).catch(err => [err])
}

相关问题