AngulaJS UI-router retry promise - javascript

I am using ui-router in my angular project. My question is: What's the best practice to retry and handle correctly a promise inside a resolve?
Right now I am simulating a disconnection or timeout, when that happens the promise is rejected(with a 404), which leaves my application in an inconsistent state. I can't find the best way to retry going to that state when the server is back up, right now nothing happens because the promise was already rejected.
PS. from ui-router wiki, not sure if I couldn't find my answer there, this is the closest thing, which I guess that Ed forgot about it: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-lazy-load-states
UPDATE(4/30 3:02pm):
While creating the plunkr example, i realized that the problem is that I'm using a service to return the promise object, then that's why the promise stays as rejected.

UPDATE(5/01 11:30AM)
SOLUTION
After playing with the plunkr last night I realized that I need to check the state of the promise, so I found this which is not too useful. By the way, I am using a service because I only need to resolve that promise once, is just retrieving a catalog from the server side that won't change for the rest of the session. So, just if you are curious, my solution will involve some kind of factory of promises(http gets), so if the promise of the service hasn't been resolved I can create a new one and go to the correct state.

Well, the direct answer is, you don't. Promises are only resolved or rejected once, and a failed resolve fails the transition. If you want to recover the transition itself, intercept $stateChangeError (or use the error callback of the transition), examine the promise rejection, and attempt to recover and re-initiate the transition. You may want to add some fail-safe code to ensure you don't do this repeatedly.

Related

Can a promise be safely 'swallowed'?

I'm given a promise and am returning it at the end of my function for other code to do more actions after me. A kind of middleware, if you will.
return apiCallPromise;
Lets say for some reason I wish to stop those actions from happening and "swallow" a particular promise. For example by doing the following:
if (promiseShouldBeStopped) return new Promise((resolve) => {})
return apiCallPromise;
This correctly returns a promise, however it never resolves. And so the 'promise chain' has been stopped dead in its tracks.
This seems like an anti-pattern to me as it the promise is left pending forever. Are there any bad effects of this that I should be aware of, or is this a fine technique for "filtering" promises?
Attempt to answer my own question
Does this cause memory issues?
Future code doesn't know that this promise has been filtered out, and so fails to do any "catch" or "finally" cleanup code.
In my case this is not relevant, and I want this code to take care of those errors so that the future code doesn't have to deal with them. (this means I can guarantee that onFulfilled gives the api response, and onRejected only gives an error that is actually unexpected)

Javascript promise that calls "then" immediately

I'm using JavaScript promises extensively in a single-page app I am developing. In certain contexts, I need the "then" method to run synchronously if the promise has already been resolved. For this purpose, I have written a custom promise implementation as a wrapper class, which works fine, but prevents me from using async/await. So I would like to know if there is a way to have both, since it seems to me that async/await is really just syntactic sugar around "then."
The custom promise implementation already implements the PromiseLike TypeScript interface, but apparently async/await always need a native promise. Why?
One possibility I have thought of is to replace the "then" method of a real promise object, instead of building my own wrapper on top. Will this work?
The reason it's important for "then" to be called immediately is that the end of the promise chain is a property of a React component, and the React component displays a loading indicator until the promise is resolved. Without my wrapper, the loading indicator is displayed briefly every time the component updates, which also breaks some user interaction.
Maybe there is a different way to solve this problem. This is my first dive into the world of JavaScript.
I'm using TypeScript and targeting ES6.
but apparently async/await always need a native promise.
No it does not. await works on an object that has a .then method.
Without my wrapper, the loading indicator is displayed briefly every time the component updates, which also breaks some user interaction.
That's not caused by awaiting resolved promises. The .then is executed in a microtask, which means that if the promise really resolved already, the .then will execute directly after the engine executed it's current task, so it gets executed before the browser rerenders.
let promise = Promise.resolve(1);
setTimeout(() => { // Make sure the promise resolved
console.log("sync");
promise.then(() => console.log("then"));
requestAnimationFrame(() => console.log("redraw"));
console.log("sync end");
}, 1000);
You'll see sync, sync end, then, redraw in the console.

Reject and terminate promise on external event

I want to be able to reject and stop the rest of the promise from running if an external event occurs. This is the example usecase:
new Promise((resolve,reject)=>{
websocket.onerror=reject;
//do processing here
websocket.onerror=undefined;
resolve(...);
});
This has the intended effect of rejecting the promise if an error occurs while the promise is running. However, the problem is that the rest of the promise will continue running even if a rejection occurs.
Using async/await the above is not possible at all.
I think one way would be to have every single line of code in a separate promise, and cancelling the chain on an event, but that would be a pain.
However, the problem is that the rest of the promise will continue running even if a rejection occurs.
This is a basic misunderstanding (and you're not alone in it!). There is no "rest of the promise." A promise is just a means of observing the completion of an asynchronous process. It's the process, not the promise, that's continuing.
How you cancel that process (and whether you can) depends entirely on what that process is and whether it provides a means of cancelling it, which is unrelated to promises themselves. You seem to be using a web socket, so you'd need to use the web socket API to cancel whatever you have it doing (or to send a message to the other end to tell it to stop what it's doing).
For instance: Suppose the promise were waiting for a timer (setTimeout) to fire, and would resolve when it did. Then some other thing happens and you no longer want that. Rejecting the promise just rejects the promise, it doesn't have any effect on the timer. You'd need to cancel the timer, too (clearTimeout).
Re your edit:
I think one way would be to have every single line of code in a separate promise, and cancelling the chain on an event, but that would be a pain.
No, the code in the promise executor (the function you pass new Promise) is run synchronously. Again, there's no "rest of the code" to cancel. There may well be asynchronous callbacks in there, or a process the code starts you need to send a cancellation too, but that's not going to require putting every line in its own promise, not at all.
Understanding the answer to this question may help you:
When you create the promise, it is executed synchronously. So this line is executed:
websocket.onerror=reject;
At this point, your code begins to process. If there is an event of websocket error, it is put in the js event loop, but your promise is still executing synchronously. Then you unhook the websocket's error handler, and resolve. The promise will resolve even if there was an error. At this point the call for resolve is also added to js' event loop. Then the next js tick executes, and maybe reject is called, maybe not, but it doesn't matter at this point because you resolved synchronously, and promises never change their minds once they've resolved or rejected.
So the key takeaway here is that creating a promise executes it synchronously. It's not a thread that you can cancel while waiting for other events. The promise' resolution or rejection is executed asynchronously, but that doesn't help you at all.
To cancel a promise, you'll need some pretty basic stuff such as
if(someOtherVariableThatDeterminesCancelation){
reject()
}

Page doesn't always recognize ng-if/new $scope variables with ES6 promises

Weird issue -
So, I run code that loads a user's profile. During the code it does a check to see if the person viewing the profile is a 'friend'. If they are, it uses NG-IF and also sets a $scope.button to have new text.
However - often times I need to refresh the page several times for Angular/http-server to see this. I can see the connection is correct in console.log but the problem persists. If I don't need to refresh, I see "flickering" and watch the scope change as the page loads.
Is there a way to prevent this?
I have tried $scope.apply();.
(pulling data from firebase)
Since the promise comes from outside the AngularJS framework, the framework is unaware of changes to the model and does not update the DOM. Use $q.when to convert the external promise to an Angular framework promise.
var ref = x.child(userLoggedIn).child(allUsersArray[i].uid)
var refPromise = $q.when(ref.once('value'));
Use $q Service promises that are properly integrated with the AngularJS framework and its digest cycle.
$q.when
Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.
-- AngularJS $q Service API Reference - $q.when
i was using Promises.all and $q seems to have fixed this behavior.
Under the hood, $q.all uses $q.when for each of the promises in the object or array. This will also convert the external promises to an Angular framework promise.

JavaScript Promises and race conditions

I just started using Promises in JavaScript using the Q library. I am running into a race condition and am wondering what would be the best way to resolve it.
The problem is that Q always calls the callbacks using process.nextTick() (also mentioned in the Promises/A+ spec) which means that I might miss some state changes in the object in the time between the resolution of the promise and the time the callbacks are called. My concrete problem is that I have an incoming connection and am missing the first messages. Messages are distributed using EventEmitter.
The code looks something like this. It uses the palava-client (but the problem should be universal) and is written in CoffeeScript:
defer = q.defer()
session.on 'peer_joined', (peer) ->
defer.resolve(peer)
return defer.promise
And somewhere else
peer_promise.then (peer) ->
peer.on 'message', (msg) ->
console.log "Message received:", msg
The first messages sometimes are lost because they got emitted before the promise ever got notified. The problem does not occur using only EventEmitter and Callbacks because the callbacks are always called immediately blocking the JavaScript Thread from handling the incoming messages.
The following code never misses messages:
session.on 'peer_joined', (peer) ->
peer.on 'message', (msg) ->
console.log "Message received:", msg
Do you see any way I can solve the problem using promises? I really would like to keep using them in my abstraction layer to ensure that only one peer is accepted. Is there any other way to avoid such race conditions?
As someone who usually promotes using promises, my suggestion is:
Do not use promises here
Promises represent one time events. They are an abstraction over values, one a promise changes its state it can no longer be changed. A promise starts off as pending and changes state once to either fulfilled or rejected.
You are facing a scenario where you have many users, each user joins and needs to add events, the users might 'go away', your scenario simply doesn't describe the same linear flow promises excel at. Promises are useful for a certain scenario - they are not for every concurrency problem. Using an event-emitter here is perfectly appropriate.
Your case (a user joining) does not really represent a resolved proxy operation. The code that "doesn't miss messages" is indeed more correct.
If you still choose to use promises here
There are a few things you can do:
You can use Q's progression events and add a progress handler in the creation phase. Note that Kris (Q's author) has called progression broken, and it is being removed in the next version of Q. I recommend against it.
You can wrap the message callback to only fire once a handler has been attached - accumulate items fired with a handler when it is created (in an array) and then trigger them all when the message handler is added (after you resolve, in a .then on the deferred you return.

Categories

Resources