简体   繁体   English

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

[英]redux thunk - how dispatch data in nested array after promise finish

I want to turn all 'default text' in newArray to 'new text'. 我想将newArray中的所有“默认文本”都转换为“新文本”。 Then dispatch the array with 'new text'. 然后用“新文本”调度数组。 The problem is dispatch function is dispatching the 'default text'. 问题是调度功能正在调度“默认文本”。 Look like it does not wait for promise. 看起来它不等待承诺。 What's wrong with my promise setup in the code below? 我在以下代码中的诺言设置有什么问题?

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')
    })
}

Your input data structure is like this: 您的输入数据结构如下:

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

Your code transforms it into this: 您的代码将其转换为:

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

So at the outer level there is no way of knowing when the inner promises have finished. 因此,在外部层面,没有办法知道内部承诺何时完成。 We need extra layers of promises to move that information up the object graph. 我们需要额外的承诺来将这些信息向上移动到对象图上。 Essentially, we need: 本质上,我们需要:

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

So the top level promise can resolve when all the inner ones do. 因此,当所有内部承诺都在执行时,最高级别的承诺就可以解决。 The code that does that would look very similar: 这样做的代码看起来非常相似:

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
        };
    });
};

You can use arrow functions if you think that improves clarity (I don't): 如果您认为可以提高清晰度(可以),则可以使用箭头功能:

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
    }));
};

General remark: I have removed the callback function from your code. 一般说明:我已经从您的代码中删除了回调函数。 It contradicts the philosophy behind promises to call code continuation callbacks from within them. 它与从内部调用代码连续回调的承诺背后的哲学相矛盾。

Instead of doing this (essentially your code): 而不是这样做(本质上是您的代码):

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

do this: 做这个:

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

Note how the second variant no longer has any dependency on its caller. 注意第二个变量如何不再依赖于其调用者。 It simply carries out its task and returns the result. 它只是执行任务并返回结果。 The caller can decide what to do with it: 呼叫者可以决定如何处理它:

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

Nesting, asynchronism and the requirement to clone (or mimic) make this slightly tricky : 嵌套,异步和克隆(或模仿)的要求使这变得有些棘手:

You could build the required array as an outer variable : 您可以将所需的数组构建为外部变量:

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);
    }
}

Alternatively, it's possible to dispense with the outer variable and allow the promises to convey the data : 另外,也可以省去外部变量,并允许promise传递数据:

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);
    }
}

Barring mistakes on my part, both versions should work. 除我自己的错误外,这两个版本都应该工作。

Injection of defaults on error could be more comprehensive, if desired. 如果需要,可以将错误的默认值注入更为全面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM