前端要给力之:红绿灯大战中的火星生命-Promise

文章探讨了Promise在前端开发中的应用,以红绿灯模拟为例,阐述了如何从命令式编程思维转向Promise的思维方式。通过错误的抽象起点,逐步引导读者理解Promise的核心思想——数据就绪后进行操作。文章详细分析了如何正确处理Promise的逻辑过程,包括如何确认数据就绪、处理单个数据、理解.then()的立即返回特性,并提供了处理迭代的方法。最后,作者强调了正确抽象问题的重要性,展示了如何将问题转化为数据驱动的模型,提高代码的可读性和复用性。
摘要由CSDN通过智能技术生成

目录

传说的开始

前些日子看了三集的《浪客剑心》的电影版,它的最后一集是叫“传说的终结”。这几个字让我很感概:我不是剑心迷,我的一些80、90后朋友却是看着剑心漫画长大的,因此他们常讲的一些梗在我看来便如同究极深奥的科学谜题;然而当我有一天终于要看这“传说中的剑心”的时候,它却“终结”了。

我看这个片子纯粹是因为打得好看,看完也就知道“剑心是个在脸上画叉叉的高颜值冷男(好吧我承认为了显示我还算个跟得上时代的人我把最近听到的几乎所有的流行词以及流行的文字写法全用上了)”。然而面对这样的尴尬,究其根源却在于我是个不知道“传说的开始”的家伙。

所以,今次讲Promise,请容我从这场“红绿灯大战”的起源讲起,更早的,再讲讲我与Promise的故事。至于这样做会不会让读者对Promise这个东西有更深入或更新颖的了解,我实在不知,我只是觉得:当一个传说已经过去,而去看这个故事的人既然不知道它的起始,真是悲剧。

看到winter的代码,我的第一反应是:全无promise的精髓

公历年2015年4月10日,这天中午,天气晴好,时间是正正经的12:00的时候,裕波同学在微博上@我跟hax:

谁来当裁判?

这要裁判的便是@寒冬winter 的一段代码(winter的代码#31,在这里)。这段代码是winter向@十年踪迹 同学宣战的,原文是:

我表示不服!来PK呀!

代码在code.w3ctech上的标题也是两个字母:pk。

这就是后来史书家所称的“红绿灯大战”了。我随后回复winter的微博,写到:

老实说,你写得不怎么样。全无promise的精髓。

我一开始就把自己搅进了战局,这样不好。

不过也正是这样,才有了后面的好故事。至于现在,看客们请耐点心,请容我再讲讲更早一点的故事。

其实我了解Promise也是新近的事情

hax总是跟近最新的ECMAScript规范以及JavaScript圈子的新近话题。相反的,我则不同,我不是太追新,在JS/前端的圈子中也总是伪前端自居。所以,请原谅我这么迟才了解到Promise这个东西,甚至于我对nodejs的callback hell有深切的感受也还是新近的事情。

这是在今年元旦前后,我因为一个项目要写RESTApi接口,而选用了nodejs来写一个test case。因此,大家可以想见的,我一定会面临callback,并显而易见地会痛恨之。所以,我就就写了一个名为Continuer的项目,源代码中还写着“Callback Must Die!”。

所以,我最初想用来搞掉callback的方法,其实是表现在Continuer这个项目中的(continuer@github)。

这个项目开源了并在微博上引起了一些前端同学的兴趣。这个时候便有人提到了Promise,质疑为什么在有了Promise的情况下还要做Continuer这样的东西。随后我就在翻读微博的时候,看到了hax与@孢子响马 同学的吵架贴,在这里在这里,快来看呀,打架好好看。hax向来被我称为吵架王的(有没有周星星电影的即视感),所以他在回复时言辞激烈那是再正常不过了——所以你看我就说“hax这10年来风格依旧,奥柏伦亲王真是大爱啊(这个梗要到“冰与火之歌”中去找)”,这完全符合他“认为正确就要誓死悍卫(或称为死性不改)”的风格。

hax跟孢子响马讨论的是fibjs中解决异步的方式问题,hax的主要观点是

“fib的问题并不是说他用的人少所以不好,而是说你选的不兼容道路导致工程上要采纳这个方案有很多障碍。而这障碍来自于一个没有明显优势(如果不是劣势)的编程模型。”

在讨论其中关于“用的人多人少”的问题时,hax批评一种“(你得)用了才知道好不好”的观点时,说了一段我非常非常在意的话:

第一,你不可能所有东西都尝试一遍。第二,有些东西你抓住重点看一下就可以推导出结果了。当然我的具体意见可能是错的,可能是出于误解,可能是某些我的基本前提不对,但是希望看到针对性的反驳而不是简单来一句“爱用不用”。

hax的意思是说:有些正确性是可以推论出来的,并不因为实用经验多寡的而改变。这是我这么些年来对hax的了解中,他讲过的最哲学而又最逻辑的话(其它的大多数时候,他的哲学正确与逻辑正确是分离的,^^.)。

好了,这也就是我了解Promise的源起,它来自于另一场战争。那场战争比今次所讨论的要激烈得多。许多猛士在那场地战争中倒下了。这也包括我。我后来因为这个缘故写了一篇《关于Continuer的What与Why》来解释我为什么写Continuer这个项目(在这里),这篇文字把我面临的问题锁定在“需要一个顺序执行的序列(以用于run testcases)”。在这个问题下面,写一个轻量的Continuer模块,并不算得“一件多么不正确”的事。

hax后来接受了我的观点,一半是给我面子,另一半大概是懒得跟我吵架(我是吵架王的那个时代已经一去不返了,hax同学请继续坚持,我们这代人就靠你了)。因为,我在上面这篇文章里说Promise“在概念上仍然是基于事件触发的”,在我如今看来,这句话是大大的错了。

我相信这样的问题hax是看得到的。

我与Promise后来发生的故事

我原本打算春节期间用点时间来讨论一下javascript中关于异步的几种解决方案的,但当时忙于ngx_cc项目的开源所以耽误了。而春节之后,公司的项目追得又特别紧,所以一直拖着。

到了3月初的时候,公司项目中有一个地方需要设计一种编程模型。这种编程模型是什么样的呢?它将所有的东西都理解为“一个带有服务能力的数据”,这在scala里,就是一个actor。Ok,当任何东西都变成这样一个“独立存在的actor”时,我们该怎么编程呢?

这个时候我想到了Promise。Promise编程的核心思想其实是:

如果数据就绪(promised),那么(then)做点什么。

假定我们设定:

对于“独立存在的actor”来说,这个actor(以及actor中的部分或全部成员)是否ready,是驱动后续逻辑的唯一方式。

那么这种方式实现的框架,就是纯异步模式的框架了。因为它从逻辑上是纯异步的,而在数据上,也是原生的、自然的分布式的。

我立即开始着手这个框架了,一方面Continuer被我抛得远远的(在实用中也发现了不少的问题),另一方面我打算写的文字也被继续搁置了。而我在这个框架上要解决的第一个问题,其实是:Lua不支持Promise。

呵呵,我是要在ngx_cc这个项目上(这个项目是nginx集群通讯的,在这里)继续做些事情,当然得考虑到语言问题。于是就着手写了一个真正实现Promise的Lua库(你能找到的所有所有lua-promise库都达不到真正ECMAScript兼容)。做这件事的时候是在三亚。话说这次三亚的“F100技术领袖峰会(3月20-22)”到底有多么“技术领袖”呢?主要的表征之一,就是所有人中就只剩下我一个还在写代码的了。我一边开着会跟大家讨论软件工程、设计艺术、技术领导的风格与公司组织架构之间的关系以及传统企业的互联网转型过程中技术决策者的价值……等等,另一面写着这样一个Promise for Lua的库。

离开三亚的时候,我跟麦子同学说:Promise库写完了。麦子同学一脸茫然和无限深情地看着我:老公,你潜水的时候像条鱼。

红绿灯大战的亲历实录

红绿灯大战中,我join进去的时候已经是winter的挑战了,这事实上应该是@winter 对@十年踪迹 一次还击。十年踪迹同学最早是写了这样一个例子(十年踪迹的代码#30,在这里):

function promiseDef(async, i, j){
   
  return function(){
   
    var args = [].slice.call(arguments);
    var self = this;
    return new Promise(function(resolve, reject) {
   
      if(i != null){
        args.splice(i, 0, resolve);
      }else{
        args.push(resolve);
      }
      if(j != null){
        args.splice(j, 0, reject);
      }else{
        args.push(reject);
      }
      async.apply(self, args);
    });
  }
}

//红绿灯切换:绿 5s -> 黄 2s -> 红 5s 循环

var greenPromise = promiseDef(setTimeout, 0).bind(null, 5000);
var yelloPromise = promiseDef(setTimeout, 0).bind(null, 2000);
var redPromise = promiseDef(setTimeout, 0).bind(null, 5000);
var traffic = document.getElementById('traffic');

(function restart(){
   'use strict'
  greenPromise()
    .then(function(){
   
      traffic.className = 'yellow';
      return yelloPromise();
    })
    .then(function(){
   
      traffic.className = 'red';
      return redPromise();
    })
    .then(function(){
   
 
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值