JavaScript: рекурсивная асинхронная / обещающая функция - PullRequest
0 голосов
/ 01 мая 2018

У меня есть следующая рекурсивная функция, которая прекрасно работает, когда вывод из transformItem является синхронным, но мне было очень трудно понять, как его реорганизовать, когда transformItem возвращает обещание и все еще получает тот же тип желаемого финала вывод объекта.

function transformStack(target, stack){
        var stackItem = stack.shift();//Copy Value

        util.logData(_this.context, "Target:" + JSON.stringify(target) + " Stack:" + JSON.stringify(stack), 9);
        switch(stackItem){
            case "[]":
                for(var x=0; x < target.length; x++){
                    //Copies values so not by Ref any more
                    var nextTarget = JSON.parse(JSON.stringify(target[x]));

                    if(stack.length > 0){
                        util.logData(_this.context, "Loop[]:" + JSON.stringify(nextTarget), 8);
                        target[x] = transformStack(nextTarget, JSON.parse(JSON.stringify(stack)));
                    } else {
                        util.logData(_this.context, "TransformTarget[]:" + JSON.stringify(nextTarget), 8);
                        target[x] = transformItem(nextTarget);
                    }
                }
                break;
            default:
                //Copies values so not by Ref any more
                var nextTarget = JSON.parse(JSON.stringify(target[stackItem]));

                if(stack.length > 0){
                    util.logData(_this.context, "Loop:" + JSON.stringify(nextTarget), 8);
                    target[stackItem] = transformStack(nextTarget, JSON.parse(JSON.stringify(stack)));
                } else {
                    util.logData(_this.context, "TransformTarget:" + JSON.stringify(nextTarget), 8);
                    target[stackItem] = transformItem(nextTarget);
                }
        }
        return target;
    }

Я создал этот базовый JSFiddle, который немного лучше иллюстрирует то, что я ожидаю:

https://jsfiddle.net/fxay76k8/9/

Может ли кто-нибудь помочь направить меня в правильном направлении? Я просматривал следующее сообщение о переполнении стека, но не смог правильно применить его к своему потоку: JavaScript: вызов рекурсивных функций с обещаниями

Спасибо за вашу помощь!

Кстати, я использую Q для обещаний, но я вполне уверен, что смогу перевести любые другие библиотеки обещаний на то, что мне нужно, если кто-то может помочь мне с концепциями здесь.

1 Ответ

0 голосов
/ 01 мая 2018

Я смог заставить это работать со следующим измененным кодом:

function transformStack(target, stack){
    var stackItem = stack.shift();//Copy Value
    var targetCopy = JSON.parse(JSON.stringify(target));
    var stackCopy = JSON.parse(JSON.stringify(stack));

    if(stackItem === "[]"){
        return transformStackArray(targetCopy, stackCopy);
    }

    var nextTarget = targetCopy[stackItem];
    if (stack.length > 0)
        return transformStack(nextTarget, stackCopy).then(handleResponse.bind(this,target, stackItem));
    else
        return transformItem(nextTarget).then(handleResponse.bind(this,target, stackItem));
}

/**
 * handleResponse - Helper function for merging objects for recursive function.
 * @param original - The original passed value
 * @param attribute - The name of the field to send
 * @param updated - The updated value
 * @returns {*} - Promise - Resolves to the merged object
 */
function handleResponse(original, attribute, updated){
    original[attribute] = updated;

    return q(original);
}

function transformStackArray(target, stack){
    var deferred = q.defer();
    var promises = [];
    for(var x=0; x < target.length; x++){
        var nextTarget = JSON.parse(JSON.stringify(target[x])); //Copies values so not by Ref any more
        if(stack.length > 0){
            promises.push(transformStack(nextTarget, JSON.parse(JSON.stringify(stack))));
        } else {
           promises.push(transformItem(nextTarget));
        }
    }

    q.all(promises).then(function(updatedItem){
        deferred.resolve(updatedItem);
    }).catch(function(error){
        deferred.reject(error);
    });

    return deferred.promise;
}

Самым важным для меня было обдумать, как объединять объекты, когда новые значения повышаются в рекурсии. Это обрабатывает handleResponse.

Теперь, когда у меня есть этот ответ, то, как связан связанный StackOverflow, имеет массу смысла, но по какой-то причине мне сначала было очень сложно обдумать эту проблему.

...