[译] 深切明白 Promise 五部曲:4. 扩大题目

原文地点:http://blog.getify.com/promis…

现在,我愿望你已看过深切明白Promise的前三篇文章了。而且假定你已完整明白Promises是什么以及深切议论Promises的重要性。

不要扩大原生对象!

回到2005年,Prototype.js框架是最早提出扩大Javascript原生对象的内置prototype属性的框架之一。它们的主意是我们可以经由历程向prototype属性增加分外的要领来扩大现有的功用。

假如你对近十年Javascript编程做一个简朴的观察,比方运用google简朴搜刮下,你会发明关于这个主意有很多阻挡看法。它们都是有缘由的。

大多数开辟者会通知你:“不要扩大原生对象”或许“只在polyfill的时刻扩大原生对象”。后者意味着只有当扩大的功用已被列入范例然后你只是为了能在旧的环境中运用这些功用的时刻才能对元素对象举行扩大。

数组Push要领

设想一个实在的场景(确切发作在我身上):回到Netscape3/4和IE4的时期,当时的JS并没有现在这么友爱。作为很多明显差别中的一个,数组并没有push(..)要领来向它的尾部增加元素。

所以,一些人会经由历程下面这段代码来扩大:

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

乍一看可以以为没题目,然则你很快就会发明一些题目。

  1. 这里须要一个if来推断原生是不是有关于push(..)的支撑,假如有我们就可以运用原生的push(..)要领。

  2. 我们须要注重我们已损坏了数组对象for..in轮回行动,由于我们的push(..)要领会出现在for..in轮回的效果中。固然,你不该该在数组上运用for..in轮回,这又是别的一个话题了。

有一个和1相干的更大的题目。不仅仅是须要一个if推断:

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

我们应当问问我们本身,假如内置的push(..)完成和我们的完成不兼容怎么办?假如内置的完成接收不一样数目的参数或许不一样的参数范例怎么办?

假如我们的代码依赖于我们本身完成的push(..),然后我们只是简朴的用新的要领替代我们本身的要领,那末代码会出现题目。假如我们的完成覆蓋了内置的push(..)完成,然后假如一些JS库希冀运用内置的规范push(..)要领怎么办?

这些题目是实在发作在我身上的。我有一个事变是在一个用户的陈旧的网站上到场一个组件,然后这个组件依赖于jQuery。我们组件在其他网站都可以一般运用,然则在这个迥殊的站点却没法运用。我花了很多时候来找出题目。
终究,我定位到了上面谁人if代码片断。这里有什么题目呢?

它的push(..)完成只接收一个参数,但是jQuery中希冀是经由历程push(el1,el2,...)来挪用push要领,所以它就没法一般运转了。

Oops。

然则猜猜当我移除本来的push代码时发作了什么?在其他网站这个组件也不能运用的。为何?我照样不晓得详细是为何。我以为他们意外埠依赖于外部变量,而这些外部变量没有通报进来。

然则,真正的题目是,有人经由历程一种关于将来存在潜伏风险的体式格局扩大内置原生对象,致使这个要领在将来可以没法一般运转。

我不是唯一碰到这个题目的人。不计其数的开辟者都碰到了这类状况。我们中的大多数以为你必需异常警惕当你扩大原生JS对象时。假如你这么做了,你最好不要运用跟言语新版本中的要领名雷同的名字。

Promise扩大

为何一切的老爷爷埋怨现在Promises的炽热呢?由于那些开辟Promise“polyfills”的人好像遗忘或许扬弃了老人们的伶俐。他们最先直接往PromisePromsie.prototype上加分外的东西。

我真的须要再去诠释为何这是一个“将来的”坏点子吗?

Blue In The Face

我们可以一向争辩这个题目到死,然则依然不能转变这个实际。假如你扩大原生对象,你就是和将来仇视的,就算你以为你本身已做得很好了。

而且,你用越普通化的名字来扩大原生对象,你越有可以影响将来的人。让我们看看Bluebird库,由于它是最盛行的Promisepolyfill/库之一。它足够快然则它跟其他库比起来也更加大。

然则速率和大小并非我现在忧郁的。我体贴的是它挑选了把本身增加到Promise的定名空间上。就算它运用一个polyfill平安的体式格局,实际上并没有,实际就算它增加很多分外的东西到原生对象上。

比方,Bluebird增加了Promise.method(..):

function someAsyncNonPromiseFunc() {
    // ...
}

var wrappedFn = Promise.method( someAsyncNonPromiseFunc );

var p = wrappedFn(..);

p.then(..)..;

看起来没什么题目,是吗?固然。然则假如某天范例须要增加Promise.method(..)要领。然后假如它的行动和Bluebird有很大的区分会怎样呢?

你又会看到Array.prototype.push(..)一样的状况。

Bluebird增加了很多东西到原生的Promise。所以有很多可以性会在将来会发作冲突。我愿望我从来不须要去修复某个人的Promise扩大代码。然则,我极可以须要这么做。

将来束缚

然则这还不是最糟的。假如Bluebir异常盛行,然后很多实际中的网站依赖于这么一个扩大,倏忽一天TC39协会经由历程某种体式格局强迫防止扩大官方范例,那末这些依赖于扩大的网站都将崩溃。

你看,这就是扩大原生对象的风险地点:你为了完成你的功用然后扩大原生对象,然后就拍拍屁股把这些烂摊子留给了TC39成员们。由于你愚昧的决议Javascript的保护者只能挑选其他机制。

不相信我?这类状况已发作很屡次了。你晓得为何在19年的JS汗青中typeof null === "object"这个bug一向没法修复吗?由于太多的代码都依赖于这段代码了。假如他们修复了这个bug,那末效果可想而知。
我真的不想这类事变发作在Promsie身上。请住手经由历程扩大原生对象来定义Promise polyfill/库。

包装笼统

我以为我们须要更多不损坏范例的polyfill,像我的”Native Promise Only“。我们须要优越,稳定,机能优异然则和规范兼容的polyfill。

迥殊的,我们须要它们以便于那些须要扩大promise的人可以在这个包装上举行操纵。我们不该该很轻易取得一个Promisepolyfill然后建立我们本身的SuperAwesomePromise包装在它上面吗?

已有很多的好例子了,比方Qwhen,我本身也写了一个,叫做asnquence(async + sequence),我的是设想来隐蔽promises的,由于promise是初级别的API,所以与其给你一个简朴的笼统的东西不如隐蔽貌寝的细节。

比方,比较下下面两段代码。

原生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 );

愿望你可以经由历程这个简朴的例子看出asynquence是怎样下降运用promises来表达异步流程的难度的。它在底层完成为你建立promise,它自动把它们衔接在一起,然后为一样的组合形式供应了简朴的语法。

明显,我以为asynquence是异常使人惊异的。我以为你应当看看一些例子,然后看看人人扩大的插件,这些插件使得它能供应更多的方便。

假如asynquence不是你的菜,那末你可以再寻觅一个合适你的好用着名的笼统库。
然则请不要运用那些扩大原生Promise的库。这关于将来不是一件功德。

总结

Promise是使人惊异的而且它们正在转变很多JS开辟者编写和保护一部流程的体式格局。ES6带来的原生Promise是这个言语一个严重的成功。为了加快这个成功的历程,我们中的很多人开辟Promise polyfill和Promise库。

然则不要由于Promise带来的高兴和高兴让你忘了一个不可否认的实际:扩大原生对象是一件风险而且充溢冒险的事变,并仅仅关于库的作者也包含运用这些库的一切人。

末了,请负有责任感而且运用平安的promise扩大。我们在将来会谢谢你的。

深切明白Promise五部曲–1.异步题目
深切明白Promise五部曲–2.转换题目
深切明白Promise五部曲–3.牢靠性题目
深切明白Promise五部曲–4.扩大性题目
深切明白Promise五部曲–5.乐高题目

末了,安利下我的个人博客,迎接接见:http://bin-playground.top

    原文作者:lakb248
    原文地址: https://segmentfault.com/a/1190000000600268
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞