如何检查提取呼叫并返回同一呼叫

时间:2018-06-06 19:47:12

标签: javascript promise greasemonkey fetch-api

我需要一种获取承诺的方法,然后调用它来检查返回的值,然后将此承诺完全恢复到系统的其他部分。上下文是我尝试从GraseMonkey脚本修改fetch API,以便我可以修改返回的数据。我通过在响应上调用.json()来检查它。但是,如果我不修改数据,我需要返回一个完全代表fetch API原始调用的对象,以便页面代码看不出任何区别。但是当我尝试返回对象时,我得到一个错误,即响应已经被消耗了,现在我迷失在一堆Promise中,我似乎无法解决这个问题(I&#39 ; m不是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 :(得分:1)

fetch()会返回一个解析为response object的承诺。该响应对象的方法之一是.clone(),听起来就像它想要的那样。来自.clone()的文档:

  

Response接口的clone()方法创建一个响应对象的克隆,在各方面都相同,但存储在不同的变量中。

     如果已经使用了响应Body,

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

答案 1 :(得分:0)

我想我理解这个问题,有时你需要根据参数改变异步操作的结果

没有必要执行两次操作,我认为OP代码可以大大简化如下:

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

答案 2 :(得分:0)

与@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方法返回旧的,未改变的响应,只需create a new one

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