Get Out of a TextDecoderStream() from NodeJS - javascript

When I send an error message from my express nodejs app using res.status(400).send(err.stack);, I cannot seem to get out of the decoder stream I setup on the receiving end.
Here is my code in the browser (limited to the fetch portion):
fetch("/the/url", {
method: "POST",
body: formData,
}).then(response => {
if (response.status === 200) {
return response.blob().then((data) => {
return data;
});
} else {
return new Promise((resolve, reject) => {
let err_message = "";
let reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
reader.read().then(({done, value}) => {
// When no more data needs to be consumed, close the stream
if (done) {
reject(err_message);
return;
}
// Enqueue the next data chunk into our target stream
err_message += value;
});
}).then((res) => {
return (res)
}).catch((err) => {
return (err)
});
}
}).then((res) => {
console.log(res)
}).catch((err) => {
console.log(err)
});
I have put breakpoints on all subsequent then and catch but it never resolves/rejects.
Appreciate any pointers.

In case it's helpful to someone, you need to make a recursive call to the same function to break out properly.
As per the following :
fetch("/the/url", {
method: "POST",
body: formData,
}).then(response => {
if (response.status === 200) {
return response.blob().then((data) => {
return data;
});
} else {
return new Promise((resolve, reject) => {
let err_message = "";
let reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
reader.read().then(function processText({done, value}) {
// When no more data needs to be consumed, close the stream
if (done) {
reject(err_message);
return;
}
// Enqueue the next data chunk into our target stream
err_message += value;
return reader.read().then(processText);
});
}).then((res) => {
return (res)
}).catch((err) => {
return (err)
});
}
}).then((res) => {
console.log(res)
}).catch((err) => {
console.log(err)
});
from https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/getReader

Related

How to return asynchronous calls in JavaScript with two callbacks (WIX corvid)

The following asynchronous function returns 2 callbacks, so I did what I usually do to return the response
Added return before the fetch
Added return before the result (json.access_token)
but this time console.log(httpResponse, 'fetch json') is undefined on the console and console.log(json.access_token) return the right value.
What do I need to change?
From client
GetJSON(NewURLCode).then(httpResponse => {
console.log(httpResponse, 'fetch json')
}
From Server
GetJSON(NewURLCode){
return fetch("https://accounts.google.com/o/oauth2/token", {
"method": "post",
"headers": {
"Content-Type": 'application/x-www-form-urlencoded'
},
'body': data
}).then((httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
} else {
return Promise.reject("Fetch did not succeed");
}
}).then((json) => {
console.log(json.access_token)
return json.access_token
}).catch(err => console.log(err));
}
Unlike the previous function, the following function has only one promise and returns the right object from the client
client
insert_coll ('Token',toInsert).then((ins_result) => {consule.log(ins_result)}
Backend
insert_coll{
return wixData.update(myCollection, toUpdate, options)
.then( ( results) => {
let item = results; //see item below
return results
} )
.catch( (err) => {
let errorMsg = err;
} );
}
}
The error was not accrued because of the return statement, I added a return before httpResponse.json();
It caused because the WIX onReady component called twice...
So for solving this issue I used the following WIX solution :
$w.onReady(function () {
if (wixWindow.rendering.env === "browser") {
//your code
}})
You can return that fetch itself, and handle those stuffs in client.
Like,
Server
GetJSON(NewURLCode){
return fetch("https://accounts.google.com/o/oauth2/token", {
"method": "post",
"headers": {
"Content-Type": 'application/x-www-form-urlencoded'
},
'body': data
});
}
Client
GetJSON(NewURLCode).then(httpResponse => {
if (httpResponse.ok) {
httpResponse.json();
} else {
Promise.reject("Fetch did not succeed");
}
}).then((json) => {
console.log(json.access_token)
return json.access_token
}).catch(err => console.log(err));
}
Otherwise, just return a Promise after those are resolved in the server. Like,
Server
async GetJSON(NewURLCode){
return new Promise(async (resolve, reject) => {
try {
const httpResponse= await fetch("https://accounts.google.com/o/oauth2/token", {
"method": "post",
"headers": {
"Content-Type": 'application/x-www-form-urlencoded'
},
'body': data
});
if (httpResponse.ok) {
const json = await httpResponse.json();
resolve(res.access_token);
} else {
reject("Fetch did not succeed");
}
} catch(err) {
reject(err);
}
});
}
Client
GetJSON(NewURLCode).then(httpResponse => {
console.log(httpResponse, 'fetch json')
}).catch(err => console.log(err));

Fetch then after catch still be called even be catched [duplicate]

This question already has answers here:
Chained promises not passing on rejection
(4 answers)
Closed 3 years ago.
I want to return a fetch promise to upper layer to use, but I found even this fetch promise fail (be catched), upper layer's then still be called. Is it possible "upper layer's then" only be called when fetch success?
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return data;
})
.catch(err => {
message.error(err.toString() || "please retry");
return err;
});
}
// then I call request this way:
export function userLogin(account) {
return request(`${domain}/signin/get_accesstoken`, {
method: "POST"
}).then(data => {
// even catch be called, this then still be called. Is it possible only call this then when catch not be called ?
do something;
return data;
});
}
Second edit:
I try to return a promise in then, but look like it is not a promise be returned, I don't know why.
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return new Promise(resolve=>{
resolve(data)
});
})
.catch(err => {
message.error(err.toString() || "please retry");
return new Promise((resolve, reject)=>{
reject(err)
});
});
}
Edit third:
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return data;
})
.catch(err => {
message.error(err.toString() || "please retry");
return;
});
}
// then I call request this way:
export function userLogin(account) {
return request(`${domain}/signin/get_accesstoken`, {
method: "POST"
}).then(data => {
// add this
if (!data) {
return
}
do something;
return data;
});
}
if you want to call your upper layer's then only in case of success then throw some error in catch block of fetch instead of returning err.
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return data;
})
.catch(err => {
message.error(err.toString() || "please retry");
throw new Error('fetch failed'); // throw error
});
}

TypeError: undefined is not an object (evaluating '_this.props.auth(values.username, values.password).then')

I'm developing a ReactJS app.
I'm getting the following error "TypeError: undefined is not an object (evaluating '_this.props.auth(values.username, values.password).then')".
When the "return new Promise" is outside the "then" it works properly. Nonetheless, I want to return the promise after only the two first "then"s.
Sample of loginActions.js
export const auth = (username, password) => dispatch => {
fetch('http://localhost/webservices/login', {
method: 'post',
body: JSON.stringify({ username, password })
})
.then(res => {
if(res.ok) {
console.log("Succeeded.", res);
return res.json();
} else {
console.log("Failed.", res);
return res.json();
}
})
.then(json => {
if (json.token) {
auth_status.value = true;
return auth_status.value;
} else {
auth_status.value = false;
return auth_status.value;
}
})
.then(function(res){
return new Promise((resolve, reject) => {
dispatch({
type: VERIFY_AUTH,
payload: res
});
resolve();
})
})
.catch(err => {
console.error(err);
});
};
Sample of login.js
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log("Received values of form: ", values);
this.props.auth(values.username, values.password).then(() => {
if (this.props.auth_status === true) {
message.success("Welcome!", 3);
this.setState({
redirect: true
});
} else {
message.error("The username and password combination is incorrect", 3);
}
})
.catch(err => {
console.error(err);
});
}
});
};
Your action auth is not returning anything. The return statements in the asynchronous handlers do not return for the action itself.
You need to return a Promise in your auth() action that you resolve yourself in the third then:
export const auth = (username, password) => dispatch => {
// instantly return a new promise that
// can be resolved/rejected in one of the handlers
return new Promise((resolve, reject) => {
fetch('http://localhost/webservices/login', {
method: 'post',
body: JSON.stringify({
username,
password
})
}).then(res => {
if (res.ok) return res.json();
// your probably also want to reject here
// to handle the failing of the action
reject();
}).then(json => {
if (json.token) {
auth_status.value = true;
return auth_status.value;
} else {
auth_status.value = false;
return auth_status.value;
}
}).then(res => {
dispatch({
type: VERIFY_AUTH,
payload: res
});
// resolve the original promise here
resolve();
}).catch(err => console.error(err));
});
};

Again about async/await in javascript

My function looks like this now:
var GetImages = async() => {
var images_array = [];
await request ({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if(error){
console.log('Unable to connect');
}else if(body.meta.status === "ZERO_RESULTS"){
console.log('Uable to find that address.');
}else if(body.meta.status === 200){
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if(photo.original_size.width>photo.original_size.height){
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
//callback(images_array);
}
});
return images_array;
}
I have no idea, how return my array after i'll fill it with values. With callback it works fine, but i wanna do it with async/await methid in right way. Thank you for help.
create method to return promise for request and use that method with await
requestPromise = () => {
return new Promise(function(resolve, reject) {
request({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if (error) {
console.log('Unable to connect');
reject();
} else if (body.meta.status === "ZERO_RESULTS") {
console.log('Uable to find that address.');
reject();
} else if (body.meta.status === 200) {
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if (photo.original_size.width > photo.original_size.height) {
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
resolve(images_array)
}
});
});
}
var GetImages = async() => {
try
{
images = await requestPromise();
return images;
}
catch(e){return [];}
}

ES7 timeout for async/await fetch

I want to set timeout in my fetch method, and I follow this github issue.
from #mislav answer, we could custom timeout method like below.
// Rough implementation. Untested.
function timeout(ms, promise) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error("timeout"))
}, ms)
promise.then(resolve, reject)
})
}
timeout(1000, fetch('/hello')).then(function(response) {
// process response
}).catch(function(error) {
// might be a timeout error
})
and improved by #nodkz
function timeoutPromise(ms, promise) {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error("promise timeout"))
}, ms);
promise.then(
(res) => {
clearTimeout(timeoutId);
resolve(res);
},
(err) => {
clearTimeout(timeoutId);
reject(err);
}
);
})
}
but I want to call that method in ES7 async/await syntax, I try below way but failed.
async request() {
try {
let res = await timeout(1000, fetch('/hello'));
} catch(error) {
// might be a timeout error
}
}
and how could I use it in ES7 async/await syntax?
thanks for your time.
update
thanks for #Bergi reply, and I display my code in http request step.
ES7 fetch
'use strict';
import { configApi, } from 'tyrantdb-config';
import { timeoutPromise, } from 'xd-utils-kit';
const keyResponse = configApi.keyResponse;
const KEY_DATA = keyResponse.data;
module.exports = {
async fetchLogin(url, params, dataRely) {
let {
self, processor, route,
storage, isLocalStoraged,
email, password, _warning, } = dataRely;
self.setState({ isWait: true, });
try {
let res = await timeoutPromise(10, fetch(url, params));
if (res.status >= 200 && res.status < 300) {
let resJson = await res.json();
let resData = resJson[KEY_DATA];
let cache = {
...resData,
password,
};
if (isLocalStoraged !== true) {
processor(cache, storage);
}
global.g_user = cache;
self.setState({ isWait: false, });
// clean user info which already bind to self[this]
self.email = self.password = null;
self.isLocalStoraged = false;
route();
} else {
console.log(`[login] response code: ${res.status}`);
self.setState({ isWait: false, });
_warning();
}
} catch(error) {
console.error(error);
}
},
saveLoginState: (cache, storage) => {
storage.save({
key: 'loginState',
rawData: cache,
});
},
openURL: (url, Linking) => {
Linking.canOpenURL(url).then(supported => {
if (!supported) {
console.log(`can\'t handle url: ${url}`);
} else {
return Linking.openURL(url);
}
}).catch((err) => {
console.log(`error occurred: ${err}`);
})
},
};
ES6 fetch
'use strict';
import { configApi, } from 'tyrantdb-config';
import { timeoutPromise, } from 'xd-utils-kit';
const keyResponse = configApi.keyResponse;
const KEY_DATA = keyResponse.data;
module.exports = {
fetchLogin(url, params, dataRely) {
let {
self, processor, route,
storage, isLocalStoraged,
email, password, _warning, } = dataRely;
self.setState({ isWait: true, });
timeoutPromise(1000, fetch(url, params))
.then((res) => {
if (res.status >= 200 && res.status < 300) {
return res.json();
} else {
console.log(`[login] response code: ${res.status}`);
self.setState({ isWait: false, });
_warning();
}
})
.then((resJson) => {
let resData = resJson[KEY_DATA];
let cache = {
...resData,
password,
};
if (isLocalStoraged !== true) {
processor(cache, storage);
}
global.g_user = cache;
self.setState({ isWait: false, });
// clean user info which already bind to self[this]
self.email = self.password = null;
self.isLocalStoraged = false;
route();
})
.catch(error => console.error(error))
.done();
},
saveLoginState: (cache, storage) => {
storage.save({
key: 'loginState',
rawData: cache,
});
},
openURL: (url, Linking) => {
Linking.canOpenURL(url).then(supported => {
if (!supported) {
console.log(`can\'t handle url: ${url}`);
} else {
return Linking.openURL(url);
}
}).catch((err) => {
console.log(`error occurred: ${err}`);
})
},
};
above ES6 fetch will catch output below, I think #Bergi is right, It's my code fault, not timeoutPromise error.
2016-06-08 22:50:59.789 [info][tid:com.facebook.React.JavaScript] [login] response code: 400
2016-06-08 22:50:59.808 [error][tid:com.facebook.React.JavaScript] { [TypeError: undefined is not an object (evaluating 'KEY_DATA')]
line: 103795,
column: 29,
sourceURL: 'http://172.26.129.189:8081/index.ios.bundle?platform=ios&dev=true' }
2016-06-08 22:50:59.810 [error][tid:com.facebook.React.JavaScript] One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.
2016-06-08 22:50:59.810 [info][tid:com.facebook.React.JavaScript] 'Failed to print error: ', 'One of the sources for assign has an enumerable key on the prototype chain. This is an edge case that we do not support. This error is a performance optimization and not spec compliant.'

Categories

Resources