banner 728x90

The Dark Side of Promises

In Mobile Web Development 13 views
banner 728x90

Since the release of es6 many new functions have found their way to NodeJS, but they did not have the same impact as promises. Promises were developed for the browser before es6 was even one thing. There were several implementations that were used as the deferred jQuery object before the standard made them obsolete. Promises were pretty useful to the client, especially if you had to make a lot of asynchronous calls, or if your API was a complete mess and you had to collect calls from everywhere asynchronously. For me that was usually the case later on, at least that was when I found promises the most useful. The ability to bypass every promise and confirm as many recall campaigns as possible and link them as often as you wanted made promises very versatile, but that was true for the customer. The server is different. On the server you have to make a huge number of asynchronous calls compared to the client. The client normally only needs to call api-server asynchronously, but the server must talk to the database, the file system, external APIs such as payment and communication and any core services that you may need to use. In essence: many things. All the problems we have as a result of promises on the client are strengthened on the server because of the higher usage and the greater chance of errors.

When we look at the code that we initially use to make promises, they do not look very different from the normal functions, but there is one main feature that makes them unique. Promises catches all exceptions that are thrown into them synchronously. Although this is very useful in most cases, this can cause some problems if you are not willing to treat them. When an exception is generated, the promise is rejected and the rejected recall is called if there is one. But what happens if we do not accept the rejected state of the promise? This depends on the NodeJS version, but generally a warning is printed and the function that raised the exception is closed. Rejecting promises by throwing exceptions is something that was often used in the old browser days of promised libraries and that is considered normal, but it is actually a good thing. It is good or at least good if you really want to reject a promise, but what if you do not make a mistake because you wanted it, but because you made a mistake? In that case, you should find and repair the bug and in that specific case, when an exception causes your server to crash and print a stack trace would be very useful. So what do we get instead? In NodeJS 6 and 7 we receive an unprocessed and failed write-off that will in most cases tell us what caused the error, but not true. In knot 8 we also get a short stack trace. So upgrading to node 8 could potentially solve our problems, so as long as you can do that, you may think that this is all we need to do to solve this problem. Unfortunately, node 8 is not yet used by most companies and makes up less than 10% of the market.

gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== - The Dark Side of Promises

Since junction 7, a promised rejection warning also gives you a warning:

"DeprecationWarning: Undelivered promised denials are outdated." In the future, non-handled denials will terminate the Node.js process with a non-zero exit code. "

Note that this warning does not say that it will raise an exception, but that it will crush your server, no matter what happens. That's pretty hard, is not it? This change would certainly break a number of codes if they were implemented today. Interest in UnhandledPromiseRejectionThe profit has increased in connection with the popularity and use of promises. We can even measure how much use we make of google trends.

gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== - The Dark Side of Promises

The people who searched for this particular warning have increased significantly since native promises and this warning was presented to the node. In 2017, the number of searches doubled, which probably also means that the number of people using promises in NodeJS also doubled. Perhaps this is the reason why the button team wants to clear the warning completely from its pile.

It is understandable that in case a rejection of a promise is not handled, it is better to crash the server than just give a warning. Imagine what would happen to an API route if a rejection was not handled. In those cases, the answer would not be sent to the client because the function would close before it reached that point, but it would not close the socket either because the server would not crash, and it would just wait until after two minutes. If several such requests were made to the server within a period of two minutes, we could run out of sockets very quickly, which would block our service for good. Conversely, if we crash and restart, we should be able to serve some requests for a short time. It is clear that neither case is desirable, so we have to put a handling agent at the end of each promised chain. This prevents the server from crashing or generating a warning that also allows us to respond in some way to API requests. The problem with the catch method is that it is only a glorified reject callback that does not differ from the one supplied via the second parameter of the then promise method.

The biggest problem I have with promises is that all exceptions are intercepted by the handling agent, regardless of why they were raised. It is normal for asynchronous calls to fail and it is normal to use that option, but when you catch all exceptions, the errors in your code are also collected. If the system would crash normally and give you a stack trace with the promise, the code will try to address the exception and possibly fail by async call, while the rest of your code is executed uninterrupted. It is very difficult to distinguish between promised rejection thrown by the system and an exception thrown by the code, and even if you could just make it more than engineering. The only way to handle promises properly is to write a large number of tests, but the fact that you simply have to do that is not a positive feature in itself. Not everyone does that and not everyone is allowed, and there is no good reason to make it difficult for them.

Exceptions raised in an Async call can not be intercepted by a try-catch block, so it makes sense to catch them if necessary. The key word here is "necessary". It is not necessary to catch them during development, just as ExpressJS will not catch them, except in production, but even if caught later, it stops at least code execution for that particular call, which you do not for promises. The right way to handle exceptions in promises or other asynchronous calls is (a) to offer them an exception handler, which if provided is executed if an exception is generated and (b) the promise chain or the rest of the code of execution. This handler can be propagated in the reward chain and if it is not set up, the exception can bubble up and cause the server to crash.

Some people think that throwing in promises is necessary to reject the callback, but that was never true. Even today you can return a Promise.reject (someError) to violate any promise you would normally throw . If you wonder why wrong mistakes are used to reject promises that not many people could answer. I'm not sure if there is an answer to start with, except that this was the way promises for the browser were implemented many years ago, and ECMA simply re-applied this slightly broken standard in ES6 and Node took it from there. Was it a good idea to introduce this version of promises to the standard and to migrate them to the server? The fact that Node leaves the standard should give us some doubt. It is not even true that promises are the only way to tackle the dreaded callback hell. There are other solutions such as async and RQ libraries that contain, for example, methods such as parallel and waterfall with which coders can perform asynchronous calls on a more organized way. In any case on the server side it is rather rare to need more than a combination of the methods that these libraries offer. The reason why promises were introduced in the standard could simply be because they were popular thanks to jQuery. Implementing exception handling would be easier with a traditional async library, but that does not mean it is not possible with promises. Even today, you could ignore the then method on the Promise prototype and the Promise constructor to do so.

Promise.prototype.then = (function () {
const than = Promise.prototype.then;
const fixCall = function (promise, next) {
if (! next) 
return function (fall) 
};
return function (success, failure, error)  wrong;
lets promise = then.call (this, fixCall (this, success), fixCall (this, fail));
promise.error = this.error;
promise back;

} ());
function createPromise (init, error) 

I mentioned earlier that async calls can not be received by a try-catch block and that is even true within a promise, so it is possible to break a promise using a setTimeout or a set up Call . So if we catch an exception, we do so only if an exception handler is specified, in which case we call it instead. In both cases we want to prevent the rest of the promise chain from being executed and we can do so by simply giving back an empty promise that will never be resolved. It is clear that this code is only here to show that this can be done, and although you can now handle exceptions, you have not lost any of the original functionality.

A big problem with promises is that you might use them without realizing it. There are a number of popular libraries that use promises behind the scenes and at the same time allow you to specify traditional callbacks, but they will perform within the promises they use. What this means is that every exception is caught without your knowledge or ability to add a handler for them, so they will increase the Unhandled Appeals Agreement for now. You will certainly scratch your head if you see this warning without having a single promise in your code, in the same way as I did some time ago. Normally you get a relatively handy error message in the warning, but if you run the bad code in an async library method, it will probably fail as most of us can not. After you have entered a promise, all your callbacks are executed in the context of that promise and unless you drop out with something like setTimeout it will take all your code without you realizing it. I will set an example here that uses an older version of the Monk MongoDB module. This bug has been fixed, but you can never know if another library will do something similar. So, knowing that that monk uses promises, what do you think will happen if I run this code in an empty database?

async.parallel (, function (err, result) );

The answer is:

 (node: 29332) UnhandledPromiseRejectionWarning: undelivered promised rejection (rejection id: 1): Error: callback was already called. 

Unless you use Node 8, in which case you get:

(node: 46955) UnhandledPromiseRejectionWarning: unprocessed rejection of a promise. This error was caused by throwing in an async function without a catch block, or by rejecting a promise that was not handled with .catch (). (rejection id: 1)
(node: 46955) UnhandledPromiseRejectionWarning: Error: callback was already called.
at /node_modules/async/dist/async.js:955:32
at /node_modules/async/dist/async.js:3871:13
on /node_modules/monk-middleware-handle-callback/index.js:13:7
on 
on process._tickCallback (intern / process / next_tick.js: 188: 7)

Good luck finding the cause of that 😊.

Sources:

  1. https://semaphoreci.com/blog/2017/11/22/nodejs-versions-used-in-commercial-projects-in-2017.html
  2. https://trends.google.com/trends/explore?date=2016-03-30%202018-03-30&q=UnhandledPromiseRejectionWarning
  3. https://github.com/nekdolan/promise-tests


 Daniel Boros

About Daniel Boros

I am a full external remote web developer plus Javascript and NodeJS enthusiast. I have experience with building hybrid apps, nodeJS api servers for the backend and VueJS for web-based applications. I have worked all over the world for various small and large companies, both on location and at a distance. I have gained experience in marketing and online betting companies in general.

banner 728x90
author
Author: 
    Resetting of file changes with git
    Resetting of file changes with git
    There are many different philosophies when it
    DDoS protection by Incapsula (sponsored)
    DDoS protection by Incapsula (sponsored)
    DDoS security is an incredibly important protection
    Long e-mail discussions: Be Gone !!
    Long e-mail discussions: Be Gone !!
    We've all been working on those long
    Changes to permissions for AWS Mobile Hub
    Changes to permissions for AWS Mobile Hub
    Until recently, when you first created an

    Leave a reply "The Dark Side of Promises"

    Must read×

    Top