How to use IcedCoffeeScript in function with two callbacks? - iced-coffeescript

Let's assume I have such function (in Javascript):
function fun(success_cb, error_cb) {
var result;
try {
result = function_that_calculates_result();
success_cb(result);
} catch (e) {
error_cb(e);
}
}
And I use it like:
fun(function(result) {
console.log(result);
}, function(error) {
console.log(error.message);
});
How can I rewrite usage of this function in IcedCoffeeScript with await and defer?

I don't think there is an optimal way to do that in iced coffee script, although that post has some interesting suggestions: Iced coffee script with multiple callbacks
I would just stick to vanilla coffee script:
This is how your function would be writtent in coffee-script
fun = (success_cb, error_cb) ->
try
result = function_that_calculates_result()
success_cb result
catch e
error_cb e
and how you would call it in coffee script
fun (result) ->
console.log result
, (error) ->
console.log error.message
If you can rewrite the fun function in an "errback" style (err, result) in coffee script, that would be:
fun = (callback) ->
try
result = function_that_calculates_result()
callback null, result
catch e
callback e
you would then use it like that in iced coffeescript
await fun defer error, result
if error
console.log error.message
else
console.log result

From maxtaco/coffee-script#120:
There are two main ways to solve this issue:
Build a connector (as suggested by maxtaco):
converter = (cb) ->
cb_success = (args...) -> cb null, args...
cb_error = (err) -> cb err
return [cb_error, cb_success]
await getThing thing_id, converter(defer(err,res))...
console.log err
console.log res
Use the iced.Rendezvous lib (code sample from node-awaitajax):
settings.success = rv.id('success').defer data, statusText, xhr
settings.error = rv.id('error').defer xhr, statusText, error
xhr = najax settings
await rv.wait defer status
switch status
when 'success' then defersuccess data, statusText, xhr
when 'error' then defererror xhr, statusText, error

Related

Await to AJAX call doen't work as expected

I have the following two functions:
function scan_request(address, file_url) {
$.ajax({
type: "POST",
async: true,
crossDomain: true,
url: 'http://some_site/api/file/scan',
dataType: "text",
success: function (data, textStatus, jqXHR) {
var json = $.parseJSON(data);//get json response and parse it
$(json).each(function (i, val) {//extract data from json
$.each(val, async function (key, value) {
if (key.toLowerCase() == "jobid") {
var result = await query_request();
alert("result:" + result);
}
});
});
}
});
}
async function query_request() {
var settings = {
"async": true,
"crossDomain": true,
"url": 'http://some_site/api/file/query',
"method": "POST"
}
var res;
$.ajax(settings).then(function (response) {
alert("response: " + response);
res = response;
});
return res;
}
It first alerts result: undefined
and after it alerts: response: [object Object]
But I'm expecting for:
First alert response: [object Object]
And after alert result: [object Object]
It seems like it doesnt wait to the call: var result = await query_request(); and therefore the result is undefined and the alert appears before the inner alert, what am I missing?
You can only await a promise. (Or a function that returns a promise.)
Your query_request() should return the promise that is created by $.ajax(). And since it does not need to await anything itself, it does not need to be marked as async.
// returns a promise, i.e. can be awaited in caller
function query_request(value) {
return $.ajax({
crossDomain: true,
url: 'http://some_site/api/file/query',
method: "POST",
data: {jobid: value}
});
}
Now you can await the result of query_request() inside an async function:
$(json).each(function (i, val) {
$.each(val, async function (key, value) {
if (key.toLowerCase() == "jobid") {
var result = await query_request(value);
alert("result:" + result);
}
});
});
However, this code has a problem - it dasiy-chains the requests inside the loop, when they all could actually be running in parallel. This means it's slower than it needs to be.
Shifting the approach a bit, we can make sure that the Ajax requests are running in parallel instead of one after another:
async function (data, textStatus, jqXHR) {
var todo = [], pending, results;
// make a list of all the things we want to request
$(json).each(async function (i, val) {
$.each(val, function (key, value) {
if (key.toLowerCase() == "jobid") todo.push(value);
});
});
// request them all in parallel (=> array of promises)
pending = todo.map(query_request);
// wait for all of the results
results = await Promise.all(pending)
// ...now work with the results
}

Async / await is not working (javascript / DynamoDB)

I have a DynamoDB Put request wrapped into an async function.
async function putter(param1, param2) {
const paramsPut = {
TableName: MyTableName,
Item: {
"hashKey": param1,
"sortKey": param2,
}
};
dynamodb.put(paramsPut, function(err, data) {
if (err) {
console.log("Failure")
console.log(data)
return data
}
else {
console.log("Success")
console.log(data)
return data
}
});
};
The return for the async funtion is placed in the response function - this the should provide back a promise upon put operation was performed (either sucessfully or not sucessfully).
I then invoke this async put function from another async function:
var param1 = "50";
var param2 = "60";
async function main() {
await putter(param1 , param2)
console.log("Feedback received")
}
When I invoke this aysnc main function I would expect it to provide the Success statement from the put function prior to writing "Feedback received" as it should await the put function response.
However my console logs the "Feedback received" prior to
logging the "Success" statement in the put async function which I
was awaiting.
What am I missing here? Thanks for your support!
Try to change your code like follows:
try {
const data = await dynamodb.put(paramsPut).promise()
console.log("Success")
console.log(data)
return data
} catch (err) {
console.log("Failure", err.message)
// there is no data here, you can return undefined or similar
}
Almost every function from AWS SDK has the promise() variant to return the result as a Promise. Then you can just await the Promise. Don't mix callbacks with promises (async/await) - it makes the code hard to read, it's better to stick with one technique everywhere.

Async XMLHttpRequest not returning response when followed by code to redirect to another URL in Firefox and Safari

I am facing problem with my code in FireFox and Safari as below:
xhr = new window['XMLHttpRequest'];
xhr.onreadystatechange = function() {
if (done || xhr.readyState != 4) {
return;
}
done = true;
handleResponse(xhr.responseText, callback);
};
}
xhr.open('GET', uri+params, true);
xhr.withCredentials = true;
xhr.send(null);
function handleResponse(responseText, callback) {
var error;
var result;
try {
result = toucan.JSON.parse(responseText)['result']; //connectedAuth
logout result.
} catch (ex) {
result = undefined;
}
console.log("Result is" + result);
if (!result) {
var errorCode = 'UnknownError';
var errorMessage = 'An unknown error ocurred';
error = toucan.Base.format('%s: %s', errorCode, errorMessage);
}
invokeCallback(error, callback);
}
This is followed by redirection as :window.location.href = "index.php?module=login&method=logout";
However, I am not getting any response back from the request I made if it is followed by redirection in FireFox.
This works fine in Chrome but not in Firefox and is specific to the case when request is followed by redirection.
I do not have control on redirection code to be changed. Is there a way that the browser can be enforced to first complete the request and get the response before going for redirection while keeping the call asynchronous.
I would suggest you to use a promise, first create a function that run the ajax call that return the response from your server:
ajax_AuthUser(id,pass){
return $.ajax({
method: "POST",
url: "authUser.php",
data: { id: id, pass: pass}
})
}
Second use a done statement:
ajax_AuthUser(id,pass)
.done(function(response){
//check the response here !! maybe validate the json ?
var auth = JSON.parse(response)
if(auth.response == "approved"){
//do something here
}else{
//do other stuff here
}
}).fail(function(response){
//do something if fail
}).always(function(){
//do something after the call finished
})
If you want a live example here is a jsfiddle that show how promises work
Hope it helps

Why doesn't redux saga continue after fetch promise resolves?

I have a request function that returns a promise. response.json(). My Issue is that although it resolves, but my loadData function does not continue past my call.
export function* loadData() {
console.log("Saga: Loading Data...");
try {
const response = yield call(request, requestURL,
{ method: 'GET', credentials: 'include', headers: {
'Content-Type': 'application/json', } });
// Nothing past this point is ever touched :(
if (response.success) {
console.log("SUCCESS!!!!");
...
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
CheckStatus confirms a successful status on the data
function parseJSON(response) {
if (response.status === 204 || response.status === 205) {
return null;
}
var responseClone = response.clone();
console.log(responseClone.json());
return response.json();
}
When I run it, the console outputs the following. Confirming that my promise is resolving with the data I want. But the code still does not continue. Only does once every 50 or so tries.
SAGA: Loading Data...
[[PromiseStatus]]:"resolved"
[[PromiseValue]]:Object

AngularJS - fail resilence on $q.all()

I'm trying to fill some local data resolving a series of remote calls.
When every promise is resolved, I load the data and proceed.
The method $q.all( [] ) does exactly this:
$q.all([
this.getUserInfo(11)
.then(function (r) {
results.push(r)
}),
this.getUserConns()
.then(function (r) {
results.push(r)
}),
this.getUserCtxs()
.then(function (r) {
results.push(r)
})
])
.then(function () {
console.log(results)
})
Problem is, this code is not resilient.
If any of these call fails, nobody gets the fish!
Wrapping the calls in a try/catch statement, simply causes $q.all() to entirely ignore the entry, even when not failing (note the console.log in the func)...
$q.all([
this.getUserInfo2(11)
.then(function (r) {
results.push(r)
}),
function () {
try {
this.getUserGroups()
.then(function (r) {
console.log(r)
results.push(r)
})
}
catch (err) {
console.log(err)
}
},
])
.then(function () {
console.log(results)
})
Output:
[Object]
Any hint on how I could wrap this to be resilient?
Thanks to #dtabuenc, I've gone one step further.
Implementing the error callback, I can avoid the breaking of the chain, and push the values of the resolved promises.
However, a nasty Exception is still displayed on the console...
How can I get rid of that if I cannot try/catch on async requests?
Caller code
return $q.all([
this.getUserInfo(user_id)
.then(function (r) {
results['personal_details'] = r
}),
this.getUserConns()
.then(
function (r) {
results['connections'] = r
},
function(err) {
console.log(err)
})
])
.then(function () {
return (results)
})
Callee code (inject with an exception)
getUserConns: function() {
return __doCall( ws.getUserConnections, {} )
.then( function(r) {
// very generic exception injected
throw new Error
if (r && r.data['return_code'] === 0) {
return r.data['entries']
}
else {
console.log('unable to retrieve the activity - err: '+r.data['return_code'])
return null
}
})
},
This will work but also push the errors to the array.
function push(r) {
results.push(r);
}
$q.all([
this.getUserInfo(11).then(push).catch(push),
this.getUserConns().then(push).catch(push),
this.getUserCtxs().then(push).catch(push)
])
.then(function () {
console.log(results);
})
You should also improve your understanding of promises, you never should use try-catch with promises - when using promises, you use the .catch() method (with everything else being implicitly a try). This works for normal errors as well as asynchronous errors.
If you want to totally ignore the errors:
function push(r) {
results.push(r);
}
function noop() {}
$q.all([
this.getUserInfo(11).then(push).catch(noop),
this.getUserConns().then(push).catch(noop),
this.getUserCtxs().then(push).catch(noop)
])
.then(function () {
console.log(results);
})
I think it's easier to do :
$q.all([
mypromise1.$promise.catch(angular.noop),
mypromise2.$promise.catch(angular.noop),
mypromise1.$promise.catch(angular.noop)
])
.then(function success(data) {
//.....
});
I'm not sure what you mean by resilient. What do you want to happen if one of the promises fails?
Your try-catch won't work because the promise will fail asynchronously.
You can however pass in an error handler as the second parameter to the then() call and do whatever you wish there.
Same issue here. For those of you with for loops: inside a then response:
var tracks = [];
var trackDfds = [];
for(var i = 0; i < res.items.length; i++){
var fn = function () {
var promise = API.tracks(userId, res.items[i].id);
return promise.then(function (res) {
if (res.items.length) {
tracks.push(res.items);
}
}).catch(angular.noop);
};
trackDfds.push(fn());
}
$q.all(trackDfds)
.then(function (res) {
console.log(tracks);
});
#Esailija's answer seems like a workaround to a problem.
You can't resolve the problem outside the main contributor to the problem: $q.
It seems a bit wiser to have reject callbacks for each then (2nd argument) and in there to insert $q.reject(...).
Example:
$q.all([
this.getUserInfo(11).then(
function (response) { // UI data preparation for this part of the screen },
function (response) {
$q.reject(response);
}
),
// ...
])
.then(
function () {
// all good
},
function () {
// at least one failed
}
)
This is particularly indicated when the UI model depends on all ajax calls.
Personally I think this is the safe way to proceed anyway, because most of the times you do want to push some server messages to some toast component on the reject callbacks, or alert the user in some way (queuing 7 ajax calls doesn't mean you can't show anything because 1 failed - it means you won't be able to show some region of the screen - that needs a specialized feedback to the user).

Resources