奥义是平凡中所蕴含的不凡,能有效地用于指导实践
下定义react
首先咱们须要给模态框下一个定义,Wikipedia(这就是大名鼎鼎的维基百科,后续很是多的地方都会引用它的描述)称其为modal window或者modal dialog,我认为modal dialog更加语义清晰,更具备语义化,由于一般模态框是须要用户交互的,就像发起一个会话同样。Wikipedia这样描述:编程
The modal window is a child window that requires users to interact with it before it can return to operating the parent application, thus preventing the workflow on the application main window.
因此咱们能够这样理解:模态框是须要用户优先处理的一次交互或者会话,优先处理在JavaScript中解释为阻断线程,等待用户作出响应(此处须要举一反一地知道还应该有非模态框)。下定义的要义是要使你描述的事物区别于其余,从而让咱们可以明确这是模态框而不是一个橘子或者水杯。那么模态框的实现必定要尊重其定义,或者说按照其定义实现。react-native
事实上全部JavaScript的功能都是这样被定义而且实现的,只是咱们称其为标准,也许说ECMA-262你会更熟悉一些。若是你放开眼界,就会发现,人们对于下定义的运用远不止于此,全世界都在绞尽脑汁已图对其善加利用。数组
下定义的意义和运用浏览器
当咱们还在纠结于下定义的枯燥无味的时候,还在嫌弃的时候,咱们没有意识到下定义不是全部人都有资格作的,只有那些最初的开创者和发现者才真正的有资格对他们开创和发现的东西下定义,命名也是同样,还记得那句谁发现谁命名吗?因此你在中学时候学到的无比嫌弃的说明文的下定义方法,其实其自己是至高的荣誉,而且只属于不断开拓的人(这个位置还应该触类旁通的知道说明文还有那些经常使用的描述方法,由于他们竟然能够和下定义并列,必定有神奇之处)。app
做为普通人,对下定义的善加利用表如今你真正的理解某一个事物,由于只有你真正理解他的时候你才能正确的定义它。换位思考,若是你想知道你是否真正的理解了一个事物,最简单的办法就是给他下个定义。 举个简单的例子,JavaScript的数组有一个reduce方法,咱们能够理解为概括的意思,由于它跟数学概括法的前半部分很像,因而你能够知道他是不断的运用数组的每一项值推导出一个最终的结果,再因而你能够猜到它应该有些什么参数,再加上你的经验记忆,你就能明确的知道它有些什么参数,这就是联想记忆法。dom
真正的联想记忆法必定是推导而来的,运用的是一种归一的思想,由于这正是计算机最初被设计的思想,它是二进制的,无论如今它的能力有多么的强悍,最终都是能够归到0和1的。JavaScript也遵循这一规则,它归于一切皆是对象。换位思考,整个JavaScript均可以由一切皆是对象推导出来,这原本是第一课,可是我们后面再来分析。异步
这时候咱们可能须要回顾一下咱们是如何经过对reduce下定义从而不断推导、理解、而且运用这个方法的,这里再也不赘述。ide
一样,react-native 有一个新的方法或者概念叫作reducer,这个东西就不太好理解,并且是区别于数组reduce的概括的意思的,到目前为止我没法对它下一个特别明确的定义,而且这个定义能反应出它的设计思想。你们能够运用下定义的方法对其进行更深刻的学习,共勉。函数
参考原生模态框实现
言归正传,尽管ECMA的文档极尽艰难晦涩,但这倒是解决问题的通常方法,通常方法的共同特色都是自由散漫,简单到你不相信他能发挥巨大的价值。将其用于抽象设计,这就是抽象设计的第一步—对你想实现的东西下一个定义。
因此咱们能够这么理解,为了实现模态框的优先处理,JavaScript采用了阻塞线程的实现方式来100%防止代码被继续执行,直到用户作出响应。既然JavaScript自身已经提供了模态框,而咱们尽然还要从新对其进行设计和封装,那就不得不思考一下为何咱们要这么作了。解决这种二选一的为何的最为简单而且行之有效的方法叫作swot分析。
那么什么叫作swot分析,现学现用,或者学以至用,咱们给他下一个定义,那就是权衡利弊,根据利大于弊或者弊大于利作出取舍。你的记忆中必定或多或少有这样一句讨厌的话:请分析一下你有什么优点?有什么缺点? 这时候你可能恍然大悟:靠,这不是三岁的时候跟小伙伴分饼干所用的方法吗? 是的,但这并不影响它成为威震天下的swot分析法,这也正暗合通常方法的共同特色。很是多的重大决定就是这样作出的。
那么JavaScript实现的alert和confirm究竟有什么问题呢?第一个问题就是它会阻塞线程,众所周知,JavaScript是单线程的,线程资源是很是宝贵的,若是你熟悉JavaScript,你会知道JavaScript最经典的特性之一就是异步,固然异步也是由这个单线程执行了,这就更显现出了这个线程的难得之处,绝不吝啬的说,容不得半点浪费。固然,除此以外,丑是其次的,相比之下不值得提起(全部的相比内部实现都是由swot分析负责实现的)。能够参照一个简单的实例,定时2s以后执行一些事务(好比统计时间),但在设置定时以后马上弹窗:
var startTime = Date.now(); function calculateElapsedTime() {/*{{{*/ var elapsedTime = (Date.now() - startTime)/1000; console.log('elapsedTime:', elapsedTime); }/*}}}*/ setTimeout(calculateElapsedTime, 0); alert('click ok to continue'); console.log('you will say this right after you click ok');
事实上这段代码的全部console输出都将被无限延期直到用户处理完弹窗为止。固然这段代码表面看起来不够简洁,但它其实包含了很是多的细节,在这个匿名函数被滥用、块级做用域缺失、语义化随意的时代,有不少细节值得咱们深究,这部分咱们容后再讨论。包括setTimeout的性能问题,以及JavaScript单线程所带来的问题或者说能够归一到JavaScript单线程的问题。
至此咱们均可以看到,一个基本的诉求就是,在弹窗的同时JavaScript可能须要继续执行它该执行的事务,由此能够引伸的讨论不少,相信不少人都遇到过弹窗的同时点不了回退按钮,非得关掉弹窗才能回退,因此不少现代浏览器多了一个禁止再次弹框的复选框,在一些浏览器上,好比Safari(version 9.1.1),alert弹出的同时,console无法使用。
现代模态框的设计
改进了这种种以后(出现问题并进行不断的改进,其实也就是当今互联网快速迭代的核心驱动力之一),咱们但愿的一个模态框是这样的:
长得好看(看脸时代无需过多讨论)
不阻塞线程,能够一边弹窗,一边继续执行任务跑得飞起
点击回退按钮无压力后退,无需关闭已经出现的模态窗,特别在SPA应用中尤其重要
弹窗不能重叠(dom只有一套,实际上不会重叠,这里指多个消息重叠时处理的灵活性)
须要在不关闭弹窗的基础上更新呈现的消息以及处理措施
绕过了线程阻塞,可让咱们有更大的发挥空间,但请记住Linux申请权限时的经典名言:能力越大责任越大。拥有了一边弹窗,一边执行任务的能力以后,意味着你得清楚的知道哪些代码应该在弹窗以前执行,哪些应该在弹窗后执行,哪些又该在弹窗的过程当中继续执行,而且规划好他们的结构。
为了可以使弹窗不重叠,这里须要引入队列,全部弹窗以及相应的操做按队列方式执行,这也就解释了统一的回收机制,这就让你有能力任什么时候候清空队列,回收全部弹窗,这也解释了当有超过一个弹窗的时候,咱们能够直接无闪烁更新内容和操做或者等待用户操做以后顺序弹窗(这里的弹窗指alert和confirm)。读到这里,你可能恍然大悟,这不就是单例吗,是的,可是同时你也得明白单例并无什么特别之处,也不能取代你真正的设计和实现,由于你得记住,无论你怎么设计和实现,最后你只申请一个实例,它就变成了单例(固然有一点你得清楚,不要重复添加dom节点)。
这些设计和实现细节无非是对咱们定义的模态框的设计和实现,固然它同时也是任务的分解,咱们常常在工做中或者会议上看到大领导提出目标,而后相应的负责人作任务分解,看起来和听起来都索然无味,但这倒是作好事情相当重要的方法。虽然咱们抽象设计的过程跟公司或者企业的目标比起来微不足道,但作事的原理和方法是想通的。由于一个一样简单的道理,你得对这件事很是了解才能正确的作任务分解,而清晰的理解一般是作好这件事的关键,不管是追求巨大的目标仍是作简单的抽象设计。
附言
程序是理性的,但写程序的人是感性的,而奥义原本也是平凡中所蕴含的不凡,因此这一系列的文章将更加偏向理论、哲学,是用广泛联系的思想来组织的,不只仅局限于JavaScript,也不只仅只适用于编程,因此咱们假设看这一系列文章的人都拥有良好的JavaScript基础,或者根本不关心语言自己。