In depth understanding of promise Trilogy: 4. Expansion problems

Time:2021-8-31

Original address:http://blog.getify.com/promis…

Now, I hope you have read the first three articles on understanding promise in depth. And suppose you have fully understood what promises are and discussed the importance of promises in depth.

Do not extend native objects!

Back in 2005,Prototype.jsFramework is one of the first frameworks to extend the built-in prototype attribute of JavaScript native objects. The idea is that we can extend existing functionality by adding additional methods to the prototype attribute.

If you do a simple survey of JavaScript programming in the past decade, such as using Google for simple search, you will find that there are many objections to this idea. They all have a reason.

Most developers will tell you: “don’t extend native objects” or “only extend native objects when Polyfill”. The latter means that you can only extend element objects when the extended functions have been included in the specification, and then you just want to use these functions in the old environment.

Array push method

Imagine a real scene (it did happen to me): back in the era of Netscape 3 / 4 and IE4, JS was not as friendly as it is now. As one of the many significant differences, arrays do notpush(..)Method to add an element to its tail.

Therefore, some people will extend it through the following code:

//Netscape 4 doesn't hava Array.push
Array.prototype.push = function(elem){
    this[this.length - 1] = elem ;
}

At first glance, it may seem OK, but you will soon find some problems.

  1. We need one hereifTo determine whether the native haspush(..)If there is support, we can use nativepush(..)method.

  2. We need to note that we have destroyed the array objectfor..inCyclic behavior because of ourpush(..)Method will appear infor..inThe result of the loop. Of course, you shouldn’t use it on arraysfor..inCycle, this is another topic.

There is a bigger problem related to 1. Not just oneifJudgment:

if(!Array.prototype.push){
    //make our own
}

We should ask ourselves if the built-inpush(..)What if the implementation is incompatible with our implementation? What if the built-in implementation accepts different numbers of parameters or different parameter types?

If our code depends on our own implementationpush(..)Then we simply replace our own method with a new method, and the code will have problems. If our implementation overrides the built-inpush(..)Implementation, and then if some JS libraries expect to use built-in standardspush(..)What about the method?

These problems really happen to me. One of my jobs is to add a component to a user’s ancient website, and then the component depends on jQuery. Our components can be used normally in other websites, but they can’t be used in this special site. I spent a lot of time finding out the problem.
Finally, I located the one aboveifCode snippets. What’s the problem here?

itspush(..)The implementation accepts only one parameter, but the expectation in jQuery is to passpush(el1,el2,...)To call the push method, so it won’t work properly.

Oops。

But guess what happens when I remove the original push code? This component cannot be used in other websites. Why? I still don’t know exactly why. I think they accidentally rely on external variables that are not passed in.

However, the real problem is that someone extends the built-in native object in a way that is potentially dangerous for the future, so that this method may not work normally in the future.

I’m not the only one with this problem. Thousands of developers have encountered this situation. Most of us think you have to be very careful when you extend native JS objects. If you do, you’d better not use the same name as the method name in the new version of the language.

Promise extension

Why do all the grandfathers complain about the popularity of promises? Because those developersPromise“Polyfills” seem to forget or abandon the wisdom of the old people. They began to go straight toPromiseandPromsie.prototypeAdd something extra.

Do I really need to explain why this is a “future” bad idea?

Blue In The Face

We can argue about this issue until we die, but we still can’t change this fact. If you extend native objects, you are hostile to the future, even if you think you have done well.

Moreover, the more popular you use to extend native objects, the more likely you are to influence future people. Let’s seeBluebirdLibrary, because it is the most popularPromisePolyfill / one of the libraries. It’s fast enough, but it’s bigger than other libraries.

But speed and size are not what I’m worried about now. What I care about is that it chose to add itself toPromiseNamespace. Even if it uses a Polyfill safe way, it doesn’t actually add a lot of extra things to the native object.

For example, Bluebird addedPromise.method(..):

function someAsyncNonPromiseFunc() {
    // ...
}

var wrappedFn = Promise.method( someAsyncNonPromiseFunc );

var p = wrappedFn(..);

p.then(..)..;

It doesn’t look like a problem, does it? of course. But if the specification needs to be added one dayPromise.method(..)method. Then what if its behavior is very different from Bluebird?

You’ll see it againArray.prototype.push(..)The same situation.

Bluebird adds a lot to the nativePromise。 So there are many possibilities for conflict in the future. I wish I never had to fix someone’s promise extension code. But I probably need to.

Future constraints

But that’s not the worst. If bluebir is very popular, and many real websites rely on such an extension, suddenly one day TC39 Association forces to avoid extending the official specification in some way, these websites that depend on the extension will collapse.

You see, this is the danger of extending native objects: in order to implement your functions, you extend native objects, and then pat your ass and leave these mess to TC39 members. Because of your stupid decision, JavaScript maintainers can only choose other mechanisms.

Don’t believe me? This has happened many times. Do you know why in the 19 year history of JStypeof null === "object"Can’t you fix this bug? Because too much code depends on this code. If they fix this bug, the results can be imagined.
I really don’t want this to happen inPromsieOn me. Stop defining promise Polyfill / library by extending native objects.

Packaging abstraction

I think we need more Polyfill that doesn’t break the specification, like mine“Native Promise Only“。 We need Polyfill that is good, stable, excellent performance but compatible with standards.

In particular, we need them so that those who need to extend promise can operate on this package. We shouldn’t get one easilyPromisePolyfill and then create our ownSuperAwesomePromiseIs it wrapped on it?

There are many good examples, such asQandwhen, I wrote one myself, calledasnquence(async + sequence), my is designed to hide promises. Because promise is a low-level API, it’s better to hide ugly details than give you a simple abstract thing.

For example, compare the following two pieces of code.

Native promises:

function delay(n) {
    return new Promise( function(resolve,reject){
        setTimeout( resolve, n );
    } );
}

function request(url) {
    return new Promise( function(resolve,reject){
        ajax( url, function(err,res){
            if (err) reject( err );
            else resolve( res );
        } );
    } );
}

delay( 100 )
.then( function(){
    return request( "some/url" );
} )
.then(
    success,
    error
);

asynquence:

function delay(n) {
    return ASQ( function(done){
        setTimeout( done, n );
    } );
}

function request(url) {
    return ASQ( function(done){
        ajax( url, done.errfcb );
    } );
}

delay( 100 )
.val( "some/url" )
.seq( request )
.then( success )
.or( error );

I hope you can see through this simple exampleasynquenceHow to reduce the difficulty of using promises to express asynchronous processes. It creates promise for you in the underlying implementation, which automatically connects them together, and then provides a simple syntax for the same combination pattern.

Obviously, I thinkasynquenceIt’s very amazing. I think you should see someexample, and then look at what you’ve expandedplug-in unit, these plug-ins make it more convenient.

IfasynquenceIf it’s not your dish, you can find a well-known abstract library suitable for you.
But don’t use those native extensionsPromiseLibrary for. This is not a good thing for the future.

summary

Promise is amazing, and they are changing the way many JS developers write and maintain a process. Native from ES6PromiseThis is a major victory for the language. In order to accelerate this victory, many of us developed promise Polyfill and promise libraries.

But don’t forget an undeniable fact because of the excitement and joy brought by promise:Extending native objects is dangerous and risky, and only for the authors of the libraries, including everyone who uses them.

Finally, be responsible and use secure promise extensions. We will thank you in the future.

In depth understanding of promise trilogy — 1. Asynchronous problem
In depth understanding of promise trilogy — 2. Transformation problem
In depth understanding of promise trilogy — 3. Reliability
In depth understanding of promise trilogy — 4. Scalability
In depth understanding of promise trilogy — 5. LEGO problem

Finally, welcome to Amway’s personal blog:http://bin-playground.top