typescript 如何在async/await语法中拒绝?

lo8azlld  于 2023-02-25  发布在  TypeScript
关注(0)|答案(8)|浏览(225)

如何拒绝async/await函数返回的承诺?
例如,最初:

foo(id: string): Promise<A> {
  return new Promise((resolve, reject) => {
    someAsyncPromise().then((value)=>resolve(200)).catch((err)=>reject(400))
  });
}

转换为async/await

async foo(id: string): Promise<A> {
  try{
    await someAsyncPromise();
    return 200;
  } catch(error) {//here goes if someAsyncPromise() rejected}
    return 400; //this will result in a resolved promise.
  });
}

那么,在这种情况下,我怎么能恰当地拒绝这个许诺呢?

7gcisfzg

7gcisfzg1#

最好的办法是用throwError Package 值,这会导致用Error Package 值的被拒绝的承诺:

} catch (error) {
    throw new Error(400);
}

你也可以只取throw的值,但是没有堆栈跟踪信息:

} catch (error) {
    throw 400;
}

或者,返回一个被拒绝的promise,用一个Error Package 该值,但它不是惯用的:

} catch (error) {
    return Promise.reject(new Error(400));
}

(Or只有return Promise.reject(400);,但同样没有上下文信息。)
在您的示例中,由于您使用的是TypeScript,并且foo的返回值是Promise<A>,因此可以使用以下代码:

return Promise.reject<A>(400 /*or Error*/ );

async/await的情况下,最后一个可能有点语义不匹配,但它确实有效。
如果你抛出一个Error,它可以很好地处理任何使用await语法消耗你的foo结果的东西:

try {
    await foo();
} catch (error) {
    // Here, `error` would be an `Error` (with stack trace, etc.).
    // Whereas if you used `throw 400`, it would just be `400`.
}
8xiog9wr

8xiog9wr2#

还应该提到的是,您可以在调用异步操作之后简单地链接catch()函数,因为在幕后仍然返回一个promise。

await foo().catch(error => console.log(error));

这样,如果您不喜欢try/catch语法,就可以避免使用它。

ygya80vv

ygya80vv3#

你可以创建一个** Package 器函数**,它接受一个promise,如果没有错误就返回数据,如果有错误就返回错误。

function safePromise(promise) {
  return promise.then(data => [ data ]).catch(error => [ null, error ]);
}

ES7和一个async函数中使用它,如下所示:

async function checkItem() {
  const [ item, error ] = await safePromise(getItem(id));
  if (error) { return null; } // handle error and return
  return item; // no error so safe to use item
}
qhhrdooz

qhhrdooz4#

编写异步函数的一个更好的方法是从一开始就返回一个挂起的Promise,然后在Promise的回调中处理拒绝和解析,而不是仅仅在出错时吐出一个被拒绝的Promise。

async foo(id: string): Promise<A> {
    return new Promise(function(resolve, reject) {
        // execute some code here
        if (success) { // let's say this is a boolean value from line above
            return resolve(success);
        } else {
            return reject(error); // this can be anything, preferably an Error object to catch the stacktrace from this function
        }
    });
}

然后,您只需在返回的promise上链接方法:

async function bar () {
    try {
        var result = await foo("someID")
        // use the result here
    } catch (error) {
        // handle error here
    }
}

bar()

来源-本教程:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

amrnrhlw

amrnrhlw5#

这并不是对@ T. J. Crowder的回答,只是一条评论,回应了下面的评论:“实际上,如果异常将被转换为拒绝,我不确定我是否真的会因为它是一个错误而感到困扰。我只抛出错误的理由可能不适用。”
如果您的代码使用的是async/await,那么使用Error而不是400拒绝仍然是一个很好的实践:

try {
  await foo('a');
}
catch (e) {
  // you would still want `e` to be an `Error` instead of `400`
}
xxhby3vn

xxhby3vn6#

我有一个建议,用一种新颖的方法正确地处理拒绝,而不使用多个try-catch块。

import to from './to';

async foo(id: string): Promise<A> {
    let err, result;
    [err, result] = await to(someAsyncPromise()); // notice the to() here
    if (err) {
        return 400;
    }
    return 200;
}

to.ts函数应从何处导入:

export default function to(promise: Promise<any>): Promise<any> {
    return promise.then(data => {
        return [null, data];
    }).catch(err => [err]);
}

学分去迪马格罗斯曼在以下link

xeufq47z

xeufq47z7#

我知道这是一个老问题,但我只是偶然发现了这个问题,这里似乎有一个错误和拒绝之间的合并,这与(至少在许多情况下)经常重复的建议相冲突,即不要使用异常处理来处理预期的情况。如果一个异步方法试图验证一个用户,但是验证失败了,那么这是一个拒绝(两种预期情况之一),而不是一个错误(例如,如果验证API不可用)。
为了确保我不是在吹毛求疵,我使用以下代码对三种不同的方法进行了性能测试:

const iterations = 100000;

function getSwitch() {
  return Math.round(Math.random()) === 1;
}

function doSomething(value) {
  return 'something done to ' + value.toString();
}

let processWithThrow = function () {
  if (getSwitch()) {
    throw new Error('foo');
  }
};

let processWithReturn = function () {
  if (getSwitch()) {
    return new Error('bar');
  } else {
    return {}
  }
};

let processWithCustomObject = function () {
  if (getSwitch()) {
    return {type: 'rejection', message: 'quux'};
  } else {
    return {type: 'usable response', value: 'fnord'};
  }
};

function testTryCatch(limit) {
  for (let i = 0; i < limit; i++) {
    try {
      processWithThrow();
    } catch (e) {
      const dummyValue = doSomething(e);
    }
  }
}

function testReturnError(limit) {
  for (let i = 0; i < limit; i++) {
    const returnValue = processWithReturn();
    if (returnValue instanceof Error) {
      const dummyValue = doSomething(returnValue);
    }
  }
}

function testCustomObject(limit) {
  for (let i = 0; i < limit; i++) {
    const returnValue = processWithCustomObject();
    if (returnValue.type === 'rejection') {
      const dummyValue = doSomething(returnValue);
    }
  }
}

let start, end;
start = new Date();
testTryCatch(iterations);
end = new Date();
const interval_1 = end - start;
start = new Date();
testReturnError(iterations);
end = new Date();
const interval_2 = end - start;
start = new Date();
testCustomObject(iterations);
end = new Date();
const interval_3 = end - start;

console.log(`with try/catch: ${interval_1}ms; with returned Error: ${interval_2}ms; with custom object: ${interval_3}ms`);

因为我对Javascript解释器的不确定性(我只喜欢一次进入一个兔子洞),所以包含了其中的一些内容;例如,我包含了doSomething函数,并将其返回值赋给dummyValue,以确保条件块不会被优化掉。
我的结果是:

with try/catch: 507ms; with returned Error: 260ms; with custom object: 5ms

我知道在很多情况下,不值得费心去寻找小的优化,但是在大规模的系统中,这些东西可以产生很大的累积差异,这是一个非常明显的比较。
所以......虽然我认为公认答案的方法在您希望必须处理异步函数中不可预测的错误的情况下是合理的,但在拒绝仅仅意味着“您将不得不执行计划B(或C,或D......)”的情况下,我认为我更喜欢使用自定义响应对象来拒绝。

5q4ezhmt

5q4ezhmt8#

如果您不想尝试/捕获,也不关心错误消息

const f = await <PromiseHandle>.catch(console.error)

或者你可以打包promise函数,这样它就可以

function p() {
    return new Promise((resolve) => {
      if (success) {
        resolve({
          data: 'success value',
          code: 200,
          msg: null
        })
      }
      if (error) {
        // # package a layer of the same format as resolve
        resolve({
          data: null,
          code: 400,
          msg: error
        })
      }
    })
  }

这是我个人对可行方案的猜测,如果你有更方便可行的方法,请告诉我

相关问题