redux thunk - 承诺完成后如何在嵌套数组中调度数据

Posted

技术标签:

【中文标题】redux thunk - 承诺完成后如何在嵌套数组中调度数据【英文标题】:redux thunk - how dispatch data in nested array after promise finish 【发布时间】:2017-04-09 01:43:20 【问题描述】:

我想将 newArray 中的所有“默认文本”转换为“新文本”。然后用“新文本”分派数组。问题是调度函数正在调度“默认文本”。看起来它不等待承诺。下面代码中我的 promise 设置有什么问题?

return dispatch => 
    let newarray =[ 
         post:[ message:'default text', message:'default text'] 
    ]
    let quests = newarray.map( (i) => 
        return i.post.map( (item) => 
            return axios.get(someLink).then( result =>
                item.message = 'new text'
                return result
            )
        )
    )

    Promise.all(quests).then( () => 
        dispatch(
            type: constant.GET_SUCCESS,
            payload: newarray
        )
    ).catch( () =>
        console.log('no result')
    )

【问题讨论】:

正如所写,映射过程不可能导致“得到我想要的数组”。如果在某个时间点 console.log(array) 记录了您的预期,那么 (a) 它是较早事件转折的产物,或者 (b) 您正在运行与您发布的内容不同的内容。 实际上数组的外观并不重要。我只想发送修改后的数据。知道承诺有什么问题吗? 【参考方案1】:

你的输入数据结构是这样的:

[
    
        post: [
            message:'default text',
            message:'default text'
        ]
    
]

您的代码将其转换为:

[
    [
        Promise<Axios>,
        Promise<Axios>
    ]
]

因此,在外部层面,无法知道内部承诺何时完成。我们需要额外的承诺层来将这些信息向上移动到对象图中。本质上,我们需要:

Promise<[
    Promise<[
        Promise<Axios>,
        Promise<Axios>
    ]>
]>

因此,当所有内部承诺都完成时,***承诺可以解决。执行此操作的代码看起来非常相似:

return function () 
    var newarray = [ post: [ message: 'default text' ,  message: 'default text' ] ];

    return Promise.all(newarray.map(function (i) 
        return Promise.all(i.post.map(function (item) 
            return axios.get(someLink).then(function (result) 
                item.message = 'new text';
            );
        ));
    )).then(function () 
        return 
            type: constant.GET_SUCCESS,
            payload: newarray
        ;
    ).catch(function (error) 
        return 
            type: constant.GET_ERROR,
            payload: 'no result ' + error
        ;
    );
;

如果你认为可以提高清晰度,你可以使用箭头函数(我没有):

return () => 
    var newarray = [ post: [ message: 'default text' ,  message: 'default text' ] ];

    return Promise.all(newarray.map( i => Promise.all(
        i.post.map( item => axios.get(someLink).then( result => 
            item.message = 'new text';
        ) )
    ))).then( () => (
        type: constant.GET_SUCCESS,
        payload: newarray
    )).catch( (error) => (
        type: constant.GET_ERROR,
        payload: 'no result ' + error
    ));
;

一般说明:我已从您的代码中删除了回调函数。它与 promise 背后的哲学相矛盾,即从它们内部调用代码延续回调。

而不是这样做(基本上是您的代码):

function bla(callback) 
   asyncFunction().then(someProcessing).then(callback);

这样做:

function blaAsync() 
   return asyncFunction().then(someProcessing);

注意第二个变体如何不再依赖于它的调用者。它只是执行其任务并返回结果。调用者可以决定如何处理它:

blaAsync().then(function (result) 
   // what "callback" would do
)

【讨论】:

【参考方案2】:

嵌套、异步和克隆(或模仿)的要求使这有点棘手:

您可以将所需的数组构建为外部变量:

function getMessagesAndDispatch(array) 
    try 
        let array_ = []; // outer variable, mimicking `array`
        let outerPromises = array.map((a, i) => 
            array_[i] =  'post': [] ; // mimicking `a`
            let innerPromises = a.post.map((item, j) => 
                array_[i].post[j] = ; // mimicking `item`
                return axios.get(getOpenGraphOfThisLink + item.message).then(result => 
                    array_[i].post[j].message = result.data;
                ).catch((e) => 
                    array_[i].post[j].message = 'default text';
                );
            );
            return Promise.all(innerPromises);
        );
        return Promise.all(outerPromises).then(() => 
            dispatch(
                'type': constant.GET_SUCCESS,
                'payload': array_
            );
        ).catch((e) => 
            console.log('no result');
            throw e;
        );
     catch(e) 
        // in case of a synchronous throw.
        return Promise.reject(e);
    

或者,可以省去外部变量并允许承诺传达数据:

function getMessagesAndDispatch(array) 
    try 
        let outerPromises = array.map(a => 
            let innerPromises = a.post.map((item) => 
                return axios.get(getOpenGraphOfThisLink + item.message).then(result => 
                    return  'message': result.data ; // mimicking `item`
                ).catch((error) => 
                    return  'message': 'default text' ; 
                );
            );
            return Promise.all(innerPromises).then((items_) => 
                return  'post': items_ ; // mimicking `a`
            );
        );
        return Promise.all(outerPromises).then((array_) => 
            dispatch(
                'type': constant.GET_SUCCESS,
                'payload': array_ // mimicking `array`
            );
        ).catch((e) => 
            console.log('no result');
            throw e;
        );
     catch(e) 
        // in case of a synchronous throw.
        return Promise.reject(e);
    

除非我犯了错误,否则两个版本都应该可以工作。

如果需要,在错误时注入默认值可能会更全面。

【讨论】:

以上是关于redux thunk - 承诺完成后如何在嵌套数组中调度数据的主要内容,如果未能解决你的问题,请参考以下文章

如何键入 Redux thunk 动作创建者以返回承诺

成功或错误后如何使用 redux thunk 重定向?

如何使用 thunk 和 useDispatch(react-redux 挂钩)从操作中返回承诺?

带有承诺的 Redux-thunk 不起作用

从 React Redux Thunk 返回承诺

ReactJS + Redux + Reduc-thunk 无法调度承诺