【问题标题】:Async function in a promise callback承诺回调中的异步函数
【发布时间】:2019-01-15 04:22:12
【问题描述】:

我正在尝试做这样的事情,但它失败了:

myAsyncFunction = async () => {
    fetchResource().then( res => {
        await fetchAnotherResource()
        ....
    })
}

在第一个承诺完成后,我想使用 await 表达式,但看起来该回调的范围不允许异步函数。

按照上面的方式,它告诉我 await 是一个保留关键字(在这种情况下它没有为 await 提取任何含义,因为我猜是范围?)

如果我像这样用async 声明匿名函数:

fetchResource().then( async (res) => {...})

我收到这样的语法错误:

ProductForm.jsx?130a:143 Uncaught (in promise) TypeError: (0 , _context.t1) is not a function

我不确定它是否相关,但这是在 React 组件内部。

是否有语法来完成我在这里尝试做的事情? (使用异步函数作为 Promise 处理程序)

编辑:相关代码(抱歉代码转储)

initializeState = async () => {
    getShopInfo(this.state.shop_id)
    .then (async (res) => {
        if (product_id) {
            ({ activeLocalization, localizations } = await this.initializeEditState(product_id, defaultLocalization, localizations))
        } else {
            ({ activeLocalization, localizations } = await this.initializeBlankState(defaultLocalization, localizations))
        }
    })
}

initializeEditState = (product_id, defaultLocalization, localizations, allCategoriesPromises) => {
    return new Promise( resolve => {
        let productPromiseArray = []; // storage for auxiliary localization requests
        let filledOutLocalizations = []; // hold localizations that have been merged with the product data 
        getProduct(product_id, defaultLocalization.localization_id)
        .then( json => {
            /* fetch object that will represent a product in state 
            * and merge it with the default localization object */
            let defaultProductState = this.setupEditProductState(json)
            defaultLocalization = Object.assign(defaultLocalization, defaultProductState)

            /* setup promise array for all other localizations */
            localizations.forEach( l => {
                productPromiseArray.push(getProduct(product_id, l.localization_id)) 
            })

            /* fetch other products and merge them with localizations */
            Promise.all( productPromiseArray )
            .then( resultArray => {
                resultArray.forEach( res => {
                    /* test for fail condition here;
                    * fail condition happens when new localizations 
                    * are registered between edits */
                    let loc = localizations.find( 
                        l => l.localization_id ==  res.data.product.localization_id
                    )
                    if (res.result) {
                        loc = Object.assign(loc, this.setupEditProductState(res))
                    } else {
                        /* Default state for this localization 
                        * (you should have access to defaultLocalization) */
                        loc = Object.assign(defaultProductState, loc)
                    }
                    filledOutLocalizations.push(loc)
                }) 
                /* Finally, get ALL category lists and
                    * INITIALIZE EDIT STATE */
                let promiseArray = []
                for (var filLoc of filledOutLocalizations) {
                    promiseArray.push(getAllCategories(filLoc.localization_id))
                }

                resolve({ activeLocalization: defaultLocalization, localizations: filledOutLocalizations })
            })
        })
    })
}

initializeBlankState = ( defaultLocalization, localizations ) => {
    return new Promise( resolve => {
        let activeLocalization = Object.assign( 
            defaultLocalization, 
            this.getBlankState(defaultLocalization.localization_id)
        )
        activeLocalization.product.enable_flg = 1
        localizations = localizations.map( l => {
            return Object.assign(l, this.getBlankState(l.localization_id))
        })
        resolve({ activeLocalization, localizations })
    })
}

【问题讨论】:

  • 这不是语法错误,这是运行时错误。您能否发布更完整的代码以便重现问题?
  • @CertainPerformance 我明白了,是的,抱歉;有点乱
  • 出于兴趣,你为什么要混合承诺/等待?为什么不等待getShopInfo
  • @EvanTrimboli 是的,我意识到这可能是一个更好的策略;我想这只是因为我正在重构旧代码并且很懒惰。你觉得这两种风格有冲突吗?
  • 不,我认为没有什么可以阻止它,尽管我认为总的来说,如果你有可用的等待/异步,使用它会“更容易”。

标签: javascript promise async-await


【解决方案1】:

该代码在您的原始版本中不起作用,因为await 只能在async 函数中使用。 then 内部的函数有自己的作用域,与外部的函数无关;因此使用await 无效。

在第二个版本中,您将async 放入then 是违反返回类型的。来自MDN definitionPromise.prototype.then

then() 方法返回一个 Promise

MDN definitionasync function

异步函数声明定义了一个异步函数,它 返回一个 AsyncFunction 对象

你可以看到这两个不应该一起使用。

一般async-await是用来代替Promise - then - catch的,不能一起使用。因此,对于您的示例函数,它应该是:

myAsyncFunction = async () => {
    const resource = await fetchResource();
    if (isValidResource(resource)) {
        const anotherResource = await fetchAnotherResource();
        ...
    }
}

对于你的函数initializeState,它使用async

initializeState = async () => {
    const res = await getShopInfo(this.state.shop_id);
    if (product_id) {
        ({ activeLocalization, localizations } = await this.initializeEditState(product_id, defaultLocalization, localizations))
    } else {
        ({ activeLocalization, localizations } = await this.initializeBlankState(defaultLocalization, localizations))
    }
}

【讨论】:

    【解决方案2】:

    从我的角度来看,async 内的 then(..) 在您的情况下是多余的。继续使用 Promises。在fetchResource().then( res => fetchAnotherResource()).then(res=>{code...}) 中,最后一个代码将等待fetchAnotherResource(..) 完成。 所以,你的代码

    .then (async (res) => {
        if (product_id) {
            ({ activeLocalization, localizations } = await this.initializeEditState(product_id, defaultLocalization, localizations))
        } else {
            ({ activeLocalization, localizations } = await this.initializeBlankState(defaultLocalization, localizations))
        }
    })
    

    可以像这样重写

    .then ((res) => product_id?
                     this.initializeEditState(product_id, defaultLocalization, localizations)):
                     this.initializeBlankState(defaultLocalization, localizations))
    )
    .then(({activeLocalization,localizations})=>{.....})
    

    【讨论】:

      猜你喜欢
      • 2022-01-26
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 2016-06-22
      • 1970-01-01
      • 2022-08-18
      • 2019-12-31
      • 2021-07-16
      相关资源
      最近更新 更多