Как проверить получение вызова и вернуть тот же вызов - PullRequest
0 голосов
/ 06 июня 2018

Мне нужен способ получить обещание, вызвать его, чтобы проверить возвращаемое значение, а затем вернуть это обещание точно так же, как это было в других частях системы.В контексте я пытаюсь изменить API выборки из скрипта GraseMonkey, чтобы я мог изменить возвращаемые данные.Я проверяю это, вызывая .json () в ответе.Однако, если я не изменяю данные, мне нужно вернуть объект, точно представляющий исходный вызов API выборки, чтобы код страницы не видел разницы.Но когда я попытался вернуть объект, я получаю сообщение об ошибке, что ответ уже использовался, и теперь я теряюсь в стеке Обещаний, которые я не могу выполнить (я не являюсь родным JS))

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

function newFetch(){
    if (needsToBeModified(arguments[0])) {

        response = null;
        return oldFetch.apply(this, arguments)
            .then(r => {
                response = r;
                return r.json();
            })
            .then(
                j => {
                    j = processJSON(j);
                    return new Promise((resolve, rej) => {
                        response.json = () => new Promise((resolve, reject) => resolve(j));
                        resolve(response);
                    });
                },
                (fail) => {
                    return oldFetch.apply(this, arguments)
                    //How can I avoid making this call here again?
                }
            );
    } else {
        return oldFetch.apply(this, arguments);
    }      
}

Пожалуйста, кто-нибудь может мне сказатьспособ заглянуть в JSON, и если это выдает ошибку, возвращая исходное обещание из fetch без необходимости повторного вызова?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 07 июня 2018

fetch() возвращает обещание, которое разрешается в объект ответа .Один из методов этого объекта ответа - .clone(), который звучит так, как будто он делает то, что вам нужно.Из документа для .clone():

Метод clone () интерфейса Response создает клон объекта ответа, идентичный во всех отношениях, но хранящийся в другой переменной.

clone () генерирует ошибку TypeError, если тело ответа уже использовано.На самом деле, основная причина, по которой clone () существует, состоит в том, чтобы разрешить многократное использование объектов Body (когда они предназначены только для одноразового использования).

Я думаю, вы можете использовать это следующим образом:

function newFetch(){
    let p = oldFetch.apply(this, arguments);
    if (needsToBeModified(arguments[0])) {
        let origResponse, cloneResponse;
        return p.then(r => {
            origResponse = r;
            cloneResponse = r.clone();
            return r.json();
        }).then(j => {
            j = processJSON(j);
            // monkey patch .json() so it is a function that resolves to our modified JSON
            origResponse.json = () => Promise.resolve(j);
            return origResponse;
        }, fail => {
            // return clone of original response
            if (cloneResponse) {
                return cloneResponse;
            } else {
                // promise was rejected earlier, don't have a clone
                // need to just propagate that rejection
                throw fail;
            }
        });
    } else {
        return p;
    }      
}
0 голосов
/ 07 июня 2018

Как и предложил @jfriend, вам потребуется clone ответа, чтобы ваш вызывающий абонент мог снова его получить после проверки JSON:

function newFetch(urlOrRequest) {
    var promise = oldFetch.apply(this, arguments);
    if (needsToBeModified(urlOrRequest)) {
        return promise.then(response =>
            response.clone().json().then(obj => {
                const result = Promise.resolve(processJSON(obj));
                response.json = () => result;
                return response;
            }, jsonErr => {
                return response;
            })
        );
    } else {
        return promise;
    }      
}

Или еще лучше,вместо того, чтобы возвращать старый, неизмененный ответ с исправленным методом json, просто создайте новый :

function newFetch(urlOrRequest) {
    var promise = oldFetch.apply(this, arguments);
    if (needsToBeModified(urlOrRequest)) {
        return promise.then(response =>
            response.clone().json().then(obj => {
                const result = JSON.stringify(processJSON(obj));
                return new Response(result, response);
            }, jsonErr => response)
        );
    } else {
        return promise;
    }      
}

В качестве альтернативы, самый простой способ - отложить ваш processJSON вызов переписанного json метода:

…
if (needsToBeModified(urlOrRequest)) {
    return promise.then(response =>
        response.json = function() {
            return Response.prototype.json.call(this).then(processJSON);
        };
        return response;
    });
}
…
0 голосов
/ 06 июня 2018

Я думаю, что я понимаю этот вопрос, чтобы сказать, что иногда вам нужно изменить результат асинхронной операции в зависимости от ее аргументов

Нет необходимости выполнять операцию дважды, и я думаю, что код OP может быть значительноупрощается следующим образом:

function newFetch() {
    return oldFetch.apply(this, arguments).then(r => {
        return (needsToBeModified(arguments[0]))? processJSON(r.json()) : r;
    });
}
...