爬虫基于回调和事件的方式去实现,回调也是被诟病已久的问题尤其是callback这种,无论是阅读还是调试都很费劲,甚至我们连代码的堆栈都看不到,这是一种反人类的写法,Promise来拜托这种痛苦的方式

传统方式实现动画效果:

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>Promiseanimation</title><style>.ball{width:40px;height:40px;border-radius:20px;/**圆角**/}.ball1{background:red;}.ball2{background:yellow;}.ball3{background:green;}</style><scriptsrc="./node_modules/bluebird/js/browser/bluebird.js"></script></head><bodyonload="init();"><divclass="ballball1"></div><divclass="ballball2"></div><divclass="ballball3"></div><scripttype="text/javascript">functioninit(){//首先拿到这三个小球varball1=document.querySelector('.ball1')varball2=document.querySelector('.ball2')varball3=document.querySelector('.ball3')/***动画函数*@param{Object}ball球*@param{Object}distance位置,把球移动到哪里*@param{Object}cb回调的callback*/functionanimate(ball,distance,cb){alert(ball)//设定一个延时setTimeout(function(){//拿到球现在距离左边距的位置varmarginLeft=parseInt(ball.style.marginLeft,10)//判断左边距移动到和我们传入的distance的时候//重叠,说明动画执行完毕if(marginLeft===distance){//直接调用回调函数cb&&cb()}else{//小球没有达到我们预期的位置//球在我们期望位置的左侧if(marginLeft<distance){marginLeft++}else{//在右侧marginLeft--}//调整球的样式ball.style.marginLeft=marginLeft+'px'//不断重复去做,直到移动到我们所期望的位置animate(ball,distance,cb)}},13)//时间越短,动画越流畅,1秒钟60帧}//调用动画_传统方式来执行动画animate(ball1,100,function(){//球从左侧向右侧移动100像素animate(ball2,200,function(){animate(ball3,300,function(){//移动完毕之后继续移动ball3animate(ball3,150,function(){animate(ball2,150,function(){animate(ball1,150,function(){//end})})})})})})}</script></body></html>

运行结果如下:


Promise方式如下:

再使用Promise方法之前先导入npm installbluebird模块,之后再用script标签来引用

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>Promiseanimation</title><style>.ball{width:40px;height:40px;border-radius:20px;/**圆角**/}.ball1{background:red;}.ball2{background:yellow;}.ball3{background:green;}</style><scriptsrc="./node_modules/bluebird/js/browser/bluebird.js"></script></head><body><divclass="ballball1"></div><divclass="ballball2"></div><divclass="ballball3"></div><scripttype="text/javascript">//首先拿到这三个小球varball1=document.querySelector('.ball1')varball2=document.querySelector('.ball2')varball3=document.querySelector('.ball3')/***动画函数*@param{Object}ball球*@param{Object}distance位置,把球移动到哪里*@param{Object}cb回调的callback*/functionanimate(ball,distance,cb){//设定一个延时setTimeout(function(){//拿到球现在距离左边距的位置varmarginLeft=parseInt(ball.style.marginLeft,10)//判断左边距移动到和我们传入的distance的时候//重叠,说明动画执行完毕if(marginLeft===distance){//直接调用回调函数cb&&cb()}else{//小球没有达到我们预期的位置//球在我们期望位置的左侧if(marginLeft<distance){marginLeft++}else{//在右侧marginLeft--}//调整球的样式ball.style.marginLeft=marginLeft+'px'//不断重复去做,直到移动到我们所期望的位置animate(ball,distance,cb)}},13)//时间越短,动画越流畅,1秒钟60帧}//如何用promise来执行动画呢,先安装一个库npminstallbluebird//要安装在该页面同层的下面functionpromiseAnimate(ball,distance){returnnewPromise(function(resolve,reject){function_animate(){//设定一个延时setTimeout(function(){//拿到球现在距离左边距的位置varmarginLeft=parseInt(ball.style.marginLeft,10)if(marginLeft===distance){//直接调用回调函数resolve()}else{//小球没有达到我们预期的位置//球在我们期望位置的左侧if(marginLeft<distance){marginLeft++}else{//在右侧marginLeft--}//调整球的样式ball.style.marginLeft=marginLeft+'px'//不断重复去做,直到移动到我们所期望的位置_animate()}},13)//时间越短,动画越流畅,1秒钟60帧}//启动调用_animate()})}promiseAnimate(ball1,100).then(function(){returnpromiseAnimate(ball2,200)}).then(function(){returnpromiseAnimate(ball3,300)}).then(function(){returnpromiseAnimate(ball3,150)}).then(function(){returnpromiseAnimate(ball2,150)}).then(function(){returnpromiseAnimate(ball1,150)})</script></body></html>

运行效果同上。

在callback中,如果调换动画的执行顺序或者增加几个或者减少几个,需要重新更改代码;

如果用promise则是一个线性的控制无论是阅读还是维护的体验上都得到了提升,

这仅仅是在浏览器中的应用,在NodeJs中回调的场景更多也更残忍,

尤其是有远程API同步和数据库查询、文件读写操作的时候,Promise就能解决这些痛点

并且也远不止于此

了解Promise需要了解如下知识

1.ES6的Promise语言标准、Promise/A+规范

Promise是针对JavaScript中的异步场景中的解决方案(传统:回调、事件机制、订阅者、等)

Promise是一个对象和JavaScript中普通的对象没有什么区别,

同时它也是一种规范,异步操作约定了统一的接口,表示一个异步操作的最终结果,

以同步的方式来写代码,执行的操作是异步的,又保证了程序的执行顺序是同步的,

只有三种状态:未完成、已完成、失败

其中中间转换过程只能发生一次并且是不可逆的;

意思是指:要么从未完成到已完成,要么从未完成到失败。

那Promise/A+规范是什么呢?

升级版,行为标准 扩展了原来的规范,约定俗成的行为,总之是一个更为标准的

不同之处:

A+规范通过术语thenable来区分promise对象

A+定义onFulfiled/onRejected必须是作为函数来调用,而且调用过程必须是异步的

A+严格定义了then方法链式调用时onFulfilled/onRejected的调用顺序

then方法定义如下:

promiseObj.then(onFulfilled,onRejected)onFulfilled=function(value){returnpromiseObj2}onRejected=function(err){}

2.如何使用

链式调用,例如:

promiseAnimate(ball1,100).then(function(){returnpromiseAnimate(ball2,200)}).then(function(){returnpromiseAnimate(ball3,300)}).then(function(){returnpromiseAnimate(ball3,150)}).then(function(){returnpromiseAnimate(ball2,150)}).then(function(){returnpromiseAnimate(ball1,150)})

3.在什么场景下使用

只要是异步编程的地方都可以使用,业务场景简单不要为了使用Promise而使用Promise


Promise库有很多,例如:

bluebird

Q

then.js

es6-promise

ypromise

async

native-promise-only

等等