【问题标题】:What should i return from this async function?我应该从这个异步函数返回什么?
【发布时间】:2019-03-10 07:56:42
【问题描述】:

我是 javascript 中 Promises 的常规用户。现在,我想尝试异步/等待。但是由于对 async/await 的了解一半,我被卡住了。

我有一个使用 Promise 的函数如下:

const asyncRequest = (funcA, b) => {
  // do some syncronous stuff. e. g. console.log
  console.log(b);
  return funcA(b)
    .then((something) => console.log(something))
    .catch((err) => console.log(err))
}

我已尝试将上述基于 Promise 的代码转换为 async/await:

const asyncRequest = async (funcA, b) => {
  // do some syncronous stuff. e. g. console.log
  console.log(b);
  try {
    const something = await funcA(b);
    console.log(something);
  } catch (err) {
    console.log(err);
  }
}

函数转换看起来很简单。但我注意到我的基于 Promise 的代码中有 return 关键字。但是在我的异步/等待代码中,我很困惑。我应该返回什么?

真实例子:

基于 Promise 的示例

const Toast = {};

const createAsyncAction = ({
  asyncRequest, types, loadingPayload = null, showToastOnError = true,
}) => (dispatch) => {
  dispatch({
    type: types.loading,
    payload: loadingPayload,
  });

  return asyncRequest()
    .then((response) => {
      if (response.isMock) { // if mock request
        dispatch({
          type: types.success,
          payload: response.payload,
        });
        return;
      }

      if ([2, 3].includes(String(response.status).substring(0, 1))) { // if request succeeds
        response.json()
          .then((res) => {
            if (res.statusCode === 1000) {
              dispatch({
                type: types.success,
                payload: res.data,
              });
              return;
            }
            dispatch({ // if its a known error by server
              type: types.failure,
              payload: {
                code: res.statusCode,
                message: res.message,
              },
            });
            if (showToastOnError) {
              Toast.error(`${res.statusCode}: ${res.message}`);
            }
          }).catch((error) => { // if response is not convertible to json
            dispatch({
              type: types.failure,
              payload: {
                code: response.status,
                message: error.message,
              },
            });
            if (showToastOnError) {
              Toast.error(`${response.status}: ${error.message}`);
            }
          });
        return;
      }

      dispatch((error) => { // if request fails with some status codes like 404, 500...
        dispatch({
          type: types.failure,
          payload: {
            code: response.status,
            message: error.message,
          },
        });
        if (showToastOnError) {
          Toast.error(`${response.status}: ${error.message}`);
        }
      });
    }).catch(() => { // if request cannot be made due to some internet or connection issue
      dispatch({
        type: types.failure,
        payload: {
          code: 0,
          message: 'Connection issue. Make sure your are connected to the internet and that your API is working',
        },
      });
      if (showToastOnError) {
        Toast.error('Connection issue. Make sure your are connected to the internet and that your API is working');
      }
    });
};

export default createAsyncAction;

异步/等待示例:

const Toast = {};

const createAsyncAction = ({
  asyncRequest, types, loadingPayload = null, showToastOnError = true,
}) => async (dispatch) => {
  dispatch({
    type: types.loading,
    payload: loadingPayload,
  });

  try {
    const response = await asyncRequest();
    if (response.isMock) { // if mock request
      dispatch({
        type: types.success,
        payload: response.payload,
      });
      return;
    }

    if ([2, 3].includes(String(response.status).substring(0, 1))) { // if request succeeds
      try {
        const jsonResponse = await response.json();
        if (jsonResponse.statusCode === 1000) {
          dispatch({
            type: types.success,
            payload: jsonResponse.data,
          });
          return;
        }
        dispatch({ // if its a known error by server
          type: types.failure,
          payload: {
            code: jsonResponse.statusCode,
            message: jsonResponse.message,
          },
        });
        if (showToastOnError) {
          Toast.error(`${jsonResponse.statusCode}: ${jsonResponse.message}`);
        }
      } catch (error) {
        dispatch({
          type: types.failure,
          payload: {
            code: response.status,
            message: error.message,
          },
        });
        if (showToastOnError) {
          Toast.error(`${response.status}: ${error.message}`);
        }
      }
      return;
    }

    dispatch((error) => { // if request fails with some status codes like 404, 500...
      dispatch({
        type: types.failure,
        payload: {
          code: response.status,
          message: error.message,
        },
      });
      if (showToastOnError) {
        Toast.error(`${response.status}: ${error.message}`);
      }
    });
  } catch (_) {
    dispatch({
      type: types.failure,
      payload: {
        code: 0,
        message: 'Connection issue. Make sure your are connected to the internet and that your API is working',
      },
    });
    if (showToastOnError) {
      Toast.error('Connection issue. Make sure your are connected to the internet and that your API is working');
    }
  }
};

export default createAsyncAction;

【问题讨论】:

    标签: javascript asynchronous ecmascript-6


    【解决方案1】:

    你不需要一个!

    任何标记为async 的函数都会返回一个promise。现在,如果您希望该承诺解决某些问题,那么您需要返回一个值。但是,由于您只是在执行console.log,它的返回值为undefined,这相当于什么都不返回(因为如果没有指定的返回值,JavaScript 将隐式返回undefined)。

    来自async docs

    异步函数是异步操作的函数 通过事件循环,使用隐式 Promise 返回其结果。

    因此,async 将隐式返回包装在 Promise 中的函数的任何返回值。

    【讨论】:

    • 我将向您展示我当前和过去的实际功能实现。然后你能解释一下区别吗?让我更新一下我的问题。
    • 我已经更新了我的问题。您能否看一下我在问题中的真实示例,然后解释其中的区别?
    • @Vishal 你的意思是它们的功能不一样,但你期望它们吗?
    • 它们在我看来是一样的。我实际上会争辩说,使用.then.catch 的第一个实际上有一个错误。您不会返回 response.json() 调用,这意味着如果外部承诺在 response.json() 之前完成,那么您将无法访问内部承诺,可能会在承诺块之外执行您在 response.json() 之前不想做的事情完成。 async/await版本没有这个问题,因为你正确await response.json()
    • 感谢您找出错误。我将使用 Promise.resolve 对其进行测试。这是个好主意。非常感谢您的帮助和您的时间。
    【解决方案2】:

    您不需要退货。这不是代码差异的原因。在您的示例中,您需要在调用 funcA(b) 时使用await,因为您想让 js 在解析时执行其他操作。

    const asyncRequest = async (funcA, b) => {
      // do some syncronous stuff. e. g. console.log
      console.log(b);
      try {
        const something = await funcA(b);
        console.log(something);
      } catch (err) {
        console.log(err);
      }
    }
    

    【讨论】:

    • 抱歉,我忘记在示例中添加 await。感谢您注意到这一点。我已经更新了这个问题。你能解释一下吗?
    • 您不需要退货。这是我在它们之间看到的唯一功能差异,这是您问题中的根本问题。如果包含await 没有解决您的问题,请edit your question 包含MCVE
    • 感谢您的回答并找出我问题中的错误。您在评论中的答案很好,但另一个答案太好了,我不能接受两个答案。再次感谢您的时间和耐心。
    【解决方案3】:

    两个函数都返回 Promises。

    在第一种情况下,这是因为您要返回一个 Promise 链。在第二种情况下,这是因为根据定义,所有async 函数都返回 Promises。所以“return a Promise”消息隐含在第二个函数中。

    当您从async 函数返回一个值时,该值就是用于解析承诺的值。如果您不返回任何内容,则使用值 undefined 解析承诺。在这种情况下,这实际上是函数.then((something) => console.log(something)) 中返回的值。这当然是undefined,所以你不需要返回任何东西。

    【讨论】:

      猜你喜欢
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-25
      • 2018-12-28
      • 2018-05-30
      • 1970-01-01
      • 2020-08-30
      相关资源
      最近更新 更多