【问题标题】:Promise resolving function returns undefinedPromise 解析函数返回未定义
【发布时间】:2021-06-03 03:01:04
【问题描述】:

我为我想使用的 API 编写了一个 util 包装器。包装器处理请求构建和令牌获取。

从'./refreshToken'导入refreshToken

/**
 * Fetch util handles errors, tokens and request building for the wrapped API calls
 * @param {string} url Request URL e.g. /chargehistory
 * @param {string} requestMethod Request Method [GET, POST, PUT, DELETE]
 * @param {object} requestBody Request Body as JSON object
 * @param {object} retryFn The caller function as object reference to retry
 * @private This function is only used as util in this class
 * @async
 */
const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
    // Block thread if the token needs to be refetched
    if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
        refreshToken()
    }        

    let request = {
        method: requestMethod,
        headers: {
            'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
            'Content-Type': 'application/json'
        }
    }
    if(requestMethod === 'POST' || requestMethod === 'PUT') {
        request.body = JSON.stringify(requestBody)
    }

    fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json)
        return json
    })
    .catch(error => console.error(error))
}

一旦解决,这将起作用并将一些 json 打印到控制台。接下来我构建了函数来使用这个抽象:

/**
 * Get a list of all completed charge sessions accessible by the current user matching the filter options.
 */
const getChargehistory = (installationId) => {
    console.log(fetchUtil(`/chargehistory?options.installationId=${installationId}`, 'GET', {}, getChargehistory))
}

哪个打印 undefined 我可以理解,虽然我确实期望一个函数引用或一个承诺。
我尝试在 fetchUtil 和调用者之前添加asyncawait fetchUtil。这给了我一个错误,没有在未定义上调用等待。我还尝试将其重新编写成一个根本不起作用的钩子。
我需要组件的 useEffect 钩子中的数据:

const Cockpit = () => {
    const { t } = useTranslation()
    const [chargehistory, setChargehistory] = useState(undefined)
    const [installationreport, setInstallationreport] = useState(undefined)

    useEffect(() => {
        setChargehistory(getChargehistory)
        setInstallationreport(getInstallationreport)
    }, [])
}

为什么我会收到undefined,我该如何解决这个问题?

【问题讨论】:

  • fetchUtil函数内部,fetch之前需要一个return关键字:return fetch(...)。另请注意,您应该在 fetchUtil 函数中处理错误,或者只是抛出错误以允许调用代码捕获并处理错误。就个人而言,我会从fetchUtil 函数中删除catch 方法调用,并在调用fetchUtil 函数的任何地方链接catch 方法。
  • 另一种解决方案是添加一个简单的回调函数作为参数并调用它,而不是在 promise 的最后一个 then 函数中返回。

标签: javascript reactjs async-await state fetch-api


【解决方案1】:

在您的fetchUtil 函数内部,它以没有返回值结束,这意味着您的fetchUtil 函数将隐式返回undefined

你说

fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json) // (1) 
        return json
    })
    .catch(error => console.error(error))

在这个函数内部,(1) 部分运行良好,对吧?

我认为,如果您像下面这样更改代码,它会起作用。

首先,像这样更新您的fetchUtil 代码。返回获取。

const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
    // Block thread if the token needs to be refetched
    if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
        refreshToken()
    }        

    let request = {
        method: requestMethod,
        headers: {
            'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
            'Content-Type': 'application/json'
        }
    }
    if(requestMethod === 'POST' || requestMethod === 'PUT') {
        request.body = JSON.stringify(requestBody)
    }

    // return fetch here! it will return a promise object. 
    return fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json)
        return json
    })
    .catch(error => console.error(error))
}

其次,像这样更新你的getChargehistory

const getChargehistory = async (installationId) => {
    const result =  await fetchUtil(`/chargehistory?options.installationId=${installationId}`, 'GET', {}, getChargehistory)
    console.log(result);
}

因为我没有完全访问您的代码的权限,所以仍然可能存在错误,但我希望这会有所帮助!

【讨论】:

  • 这确实解决了 getChargehistory(installationId) 中的问题,但它没有解决现在在 useEffect() 之后组件树中存在待处理结果的问题
  • 你的意思是setChargehistory(getChargehistory) 部分不起作用?如果是,那是因为getChargehistory 本身返回promise 对象作为挂起状态。我认为如果你想用setChargehistory 设置结果,你必须在getChargehistory 函数中进行。这个link 可能会有所帮助!
猜你喜欢
  • 1970-01-01
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-27
  • 2019-09-02
相关资源
最近更新 更多