我需要一种获取承诺的方法,然后调用它来检查返回的值,然后将此承诺完全恢复到系统的其他部分。上下文是我尝试从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返回原始承诺而不需要再次拨打电话?
感谢。
答案 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;
});
}
…