I have a function that calculates the aspect ratio of a height and a width input, and either throws an error, or returns an object with the aspect ratio.
var bestAR = dimensions.map(function(dim) {
try {
return findBestAR(dim.width, dim.height);
}
catch (e) {
return new Bacon.Error(e);
}
});
bestAR.onError(function(e) {
alert(e)
});
I can log the new Bacon.Error in my catch statement to the console and it contains the thrown error inside of findBestAR. However, it does not respond to the onError per Bacon. Maybe I'm not fully understanding how error handling in Bacon works.
.map can only change value events into value events. To change a value event into an error event (or into a different number of events), you need to use .flatMap instead.
Related
I'm trying to get all files from firebase's storage through listAll.
By the way..
storageReference.listAll().addOnSuccessListener { listResult ->
val image_task : FileDownloadTask
for (fileRef in listResult.items) {
fileRef.downloadUrl.addOnSuccessListener { Uri ->
image_list.add(Uri.toString())
println("size1 : " + image_list.size)
}
}
println("size2 : " + image_list.size)
}//addOnSuccessListener
enter image description here
Why is the execution order like this?
How do I solve it??
When you add a listener or callback to something, the code inside the listener will not be called until sometime later. Everything else in the current function will happen first.
You are adding listeners for each item using your for loop. No code in the listeners is running yet. Then your "size2" println call is made after the for loop. At some later time, all your listeners will fire.
If you want asynchronous code like this to be written sequentially, then you need to use coroutines. That's a huge topic, but your code would look something like this (but probably a little more involved than this if you want to properly handle errors). I'm using lifecycleScope from an Android Activity or Fragment for this example. If you're not on Android, you need to use some other CoroutineScope.
The calls to await() are an alternative to adding success and failure listeners. await() suspends the coroutine and then returns a result or throws an exception on failure.
lifecycleScope.launch {
val results = try {
storageReference.listAll().await()
} catch (e: Exception) {
println("Failed to get list: ${e.message}")
return#launch
}
val uris = try {
results.map { it.downloadUrl.await().toString() }
} catch (e: Exception) {
println("Failed to get at least one URI: ${e.message}")
return#launch
}
image_list.addAll(uris)
}
There is nothing wrong with the execution order here.
fileRef.downloadUrl.addOnSuccessListener { Uri ->
the downloadUrl is an asynchronous action which means it doesn't wait for the action to actually complete in order to move along with the code.
You receive the result with the success listener (at least in this case)
If you want to deal with it in a sequential way, look at coroutines.
I ma using SignalR in the browser. Some request (calling function on the server) are long and I would like to show spinner/loading-bar.
Can I somehow hook for an event when this function is started and when it returns back.
I'm trying to figure out what you mean - I think basically you want some way to hook into the start of a call and the end of a call (to load and unload a spinner)?
I've done this in two different ways - firstly as a one-off (first example), and then more systematically (the second example). Hopefully one of these will be what you need.
$.connection.myHub.server.hubMethod().done(function () {
//called on success
}).fail(function (e) {
//called on failure - I don't recommend reading e
}).always(function() {
//called regardless
spinner.close();
});
spinner.open(); // must be triggerd AFTER call incase exception thrown (due to connection not being up yet)
If you don't like that - perhaps because you call hub methods in hundreds of different sections of codes, then there are other tricks which are a bit more complicated. Lets see:
function SetupSpinnerOnCallToSignalrMethod(hubServer, method, spinnerStartCallback, spinnerEndCallback) {
var prevFunc = hubServer[method];
hubServer[method] = function () {
var ret = prevFunc.apply(this, arguments);
spinnerStartCallback(); // must be triggerd AFTER call incase exception thrown (due to connection not being up yet)
ret.always(function() {
spinnerEndCallback();
});
return ret;
};
}
//then call this for each method
SetupSpinnerOnCallToSignalrMethod($.connection.myHub.server,
"hubMethod",
function() { spinner.open(); },
function() { spinner.close(); }
);
//the server call should then work exactly as before, but the spinner open and close calls are invoked each time.
I am new to Cucumber, and trying to write some simple tests to get started. One thing I want to test is if an element is not on the page.
In my code I do:
var myBrowser = this.browser;
menu_data.hashes().forEach(function(menuItem, idx, items) {
myBrowser
.isExisting('#' + menuItem.anchor_id, function(err, isExisting) {
if (err) {
throw err;
} else {
isExisting.should.is.isfalse;
}
});
});
Everything I have tried testing isExisting has failed. I tried using assert.isfalse(isExisting), but I get an error saying assert is not there. In fact, when I try to use any methods, like should.assert.toFalse(isExisting) throws an error saying toFalse doesn't exist.
My bad. Have you tried should.be(false)
This is due to view port being too small.
Duplicate of this WebDriver element is returning false for isVisible/waitForForVisible
I have a page that lists a company's profile and shows its open jobs. I use iron-router to get the companies profile info, but use a Meteor.call to get active jobs once the page has been loaded. However, when I return a cursor it throws a stack size exceeded error.
organization.js
Template.organization.rendered = function() {
Meteor.call('getActiveJobs', function(error, jobs){
if(error){
console.log(error);
} else {
console.log(jobs);
}
});
}
collection
Meteor.methods({
.....
getActiveJobs: function(){
return Jobs.find({organizationId: user.profile.organizationId});
}
.....
});
this throws a "RangeError: Maximum call stack size exceeded" error.
However, I can return
return Jobs.find({organizationId: user.profile.organizationId}).fetch();
without an error, but I'm trying t return the cursor so it's easier to work with using handlebars, but I don't quite understand why I'm getting this error.
Please note, that the values returned from your method need to be transferred from server to client in the JSON format. It follows that you cannot return Objects which are not JSON-serializable (there are small exceptions here, but we can forget about them for now).
If you want to return a cursor you should use Meteor.publish instead of Meteor.methods, so
Meteor.publish('activeJobs', function () {
var user = Meteor.users.findOne({_id: this.userId});
return Jobs.find({organizationId: user.profile.organizationId});
});
Also, remember to call Meteor.subscribe('activeJobs') on the client as soon as you need this data set.
I'm implementing a function which returns a Stream. I'm not sure how to implement the error handling, what is best practice?
For functions which return a Future, it's best practice never to throw a synchronous error. Is this also true for functions which return a Stream?
Here's an example of what I'm thinking:
Stream<int> count() {
var controller = new StreamController<int>();
int i = 0;
try {
doSomethingThatMightThrow();
new Timer.repeating(new Duration(seconds: 1), () => controller.add(i++));
} on Exception catch (e) {
controller.addError(e);
controller.close();
}
return controller.stream;
}
In general it is true for Streams as well. The main idea is, that users should only need to handle errors in one way. Your example moves all errors to the stream.
There are circumstances where immediate errors are better (for instance you could make the error is due to a programming error and should never be handled anyways, or if you want to guarantee that a Stream never produces errors), but sending the error through a stream is almost always a good thing.
Small nit: a Stream should usually (there are exceptions) not produce any data until somebody has started listening. In your example you are starting a Timer even though you don't even know if there will ever be a listener. I'm guessing the example is reduced and not representative of your real code, but it is something to look out for. The solution would be to use the StreamController's callbacks for pause and subscription changes.
I've updated the example to take on-board Florian's comments.
In my real use case, I don't ever want to buffer the results, so I'm throwing an UnsupportedError if the stream is paused.
I've made it a terminating stream, rather than an infinite one.
If the user of this function adds a listener asynchronously after a few seconds, then they will lose the first couple of results. They shouldn't do this. I guess that's something to document clearly. Though perhaps, I could also throw an error if the subscribe state changes after the first data has been received, but before a close has been received.
Stream<int> count(int max) {
var controller = new StreamController<int>(
onPauseStateChange: () => throw new UnsupportedError('count() Stream pausing not supported.'));
int i = 0;
try {
doSomethingThatMightThrow();
new Timer.repeating(new Duration(seconds: 1), () {
if (!controller.hasSubscribers)
return;
controller.add(i++);
if (i >= max)
controller.close();
});
} on Exception catch (e) {
controller.addError(e);
controller.close();
}
return controller.stream;
}