Node.js(十二)——NodeJs中的Promise

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

传统方式实现动画效果:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Promise animation</title>
	<style>
		.ball{
			width:40px;
			height:40px;
			border-radius: 20px;/**圆角**/
		}
		.ball1{
			background: red;
		}
		.ball2{
			background: yellow;
		}
		.ball3{
			background: green;
		}
	</style>
	<script src="./node_modules/bluebird/js/browser/bluebird.js"></script>

	</head>
	<body >
		<div class="ball ball1" style="margin-left: 0;"></div>
		<div class="ball ball2" style="margin-left: 0;"></div>
		<div class="ball ball3" style="margin-left: 0;"></div>
		<script type="text/javascript">

			function init(){

				//首先拿到这三个小球
			var ball1 = document.querySelector(‘.ball1‘)
			var ball2 = document.querySelector(‘.ball2‘)
			var ball3 = document.querySelector(‘.ball3‘)

		/**
		 * 动画函数
		 * @param {Object} ball 球
		 * @param {Object} distance 位置,把球移动到哪里
		 * @param {Object} cb 回调的callback
		 */
			function animate(ball,distance,cb){
				alert(ball)
				//设定一个延时
				setTimeout(function(){
					//拿到球现在距离左边距的位置
					var marginLeft = 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(){
						//移动完毕之后继续移动ball3
						animate(ball3,150,function(){
							animate(ball2,150,function(){
								animate(ball1,150,function(){
									//end
								})
							})
						})
					})
				})
			})

			}

		</script>
	</body>
</html>

运行结果如下:

Promise方式如下:

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

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Promise animation</title>
	<style>
		.ball{
			width:40px;
			height:40px;
			border-radius: 20px;/**圆角**/
		}
		.ball1{
			background: red;
		}
		.ball2{
			background: yellow;
		}
		.ball3{
			background: green;
		}
	</style>
	<script src="./node_modules/bluebird/js/browser/bluebird.js"></script>

	</head>
	<body>
		<div class="ball ball1" style="margin-left: 0;"></div>
		<div class="ball ball2" style="margin-left: 0;"></div>
		<div class="ball ball3" style="margin-left: 0;"></div>
		<script type="text/javascript">

				//首先拿到这三个小球
			var ball1 = document.querySelector(‘.ball1‘)
			var ball2 = document.querySelector(‘.ball2‘)
			var ball3 = document.querySelector(‘.ball3‘)

		/**
		 * 动画函数
		 * @param {Object} ball 球
		 * @param {Object} distance 位置,把球移动到哪里
		 * @param {Object} cb 回调的callback
		 */
			function animate(ball,distance,cb){
				//设定一个延时
				setTimeout(function(){
					//拿到球现在距离左边距的位置
					var marginLeft = 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来执行动画呢,先安装一个库npm install bluebird
			//要安装在该页面同层的下面
			function promiseAnimate(ball,distance){
				return new Promise(function(resolve,reject){
					function _animate(){
						//设定一个延时
						setTimeout(function(){
							//拿到球现在距离左边距的位置
							var marginLeft = 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(){
					return promiseAnimate(ball2,200)
				})
				.then(function(){
					return promiseAnimate(ball3,300)
				})
				.then(function(){
					return promiseAnimate(ball3,150)
				})
				.then(function(){
					return promiseAnimate(ball2,150)
				})
				.then(function(){
					return promiseAnimate(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){
	return promiseObj2
}

onRejected = function(err){}

2.如何使用

链式调用,例如:

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

3.在什么场景下使用

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

Promise库有很多,例如:

bluebird

Q

then.js

es6-promise

ypromise

async

native-promise-only

等等

时间: 2024-12-28 14:56:27

Node.js(十二)——NodeJs中的Promise的相关文章

玩转Node.js(二)

玩转Node.js(二) 先来回顾上次的内容,上一次我们使用介绍了Node.js并写了第一个服务器端的Hello World程序,在这个Hello World程序中,请求自带的http模块并将其赋给http变量,然后调用http模块的createServer函数,这个函数会返回一个对象,这个对象有一个叫做listen的方法,而这个方法有一个数值参数,指定这个HTTP服务器监听的端口号,我们当时定义的是8888端口号.那么为什么看起来有些复杂呢?那是因为我们向createServer函数传递了一个

SpringMVC学习(十二)——SpringMVC中的拦截器

SpringMVC学习(十二)--SpringMVC中的拦截器 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.本文主要总结一下SpringMVC中拦截器是如何定义的,以及测试拦截器的执行情况和使用方法. SpringMVC中拦截器的定义和配置 SpringMVC中拦截器的定义 在SpringMVC中,定义拦截器要实现HandlerInterceptor接口,并实现该接口中提供的三个方法,如下: public class Inter

Docker学习(十二)中遇到的一些问题汇总

Docker学习(十二)中遇到的一些问题汇总 标签(空格分隔): docker docker: Error response from daemon: Conflict. The container name "/myubuntu" is already in use docker container ls docker container rm 容器名 docker rm $(docker ps -a -q) 删除所有容器 centos无法上网 ifup ens33 // 启用网卡

Node.js(十)——NodeJs事件

NodeJs的事件模块 在爬虫代码中有个on('data')事件,为什么响应的res回有一个on方法呢,那这个on做什么事情呢,要回答这些问题,要从事件模块说起,在NodeJs中不存在浏览器中的冒泡.捕获这些行为的,所以NodeJs中实现的events这个模块,里面的大多数模块都集成了这个模块, 所以events是最重要的一个模块,它只对外暴露了一个对象,就是eventImit,作用有两个分别是事件的发射,和事件的监听,两个不同的执行环节本来是毫无联系的,但是有了事件模块的支持以后,这两个环节就

Node.js(十四)——Net模块之Buffer

网络的基础是数据的传输和处理,Buffer缓冲,在NodeJs中处理二进制的数据,为什么要折腾出一个Buffer呢,因为JavaScript字符串是一个utf-8编码存储的,处理二进制的能力是很弱的,而网络层对于不同资源的请求.响应甚至是文件都是用二进制进行交互的,所以NodeJs就有了这么一个接口,专门存放二进制的缓存区,并提供了一些方法来对这些缓存区的数据进行进一步的处理, Buffer在NodeJs中是可以全局访问的,同样用require来引用和加载它: 在Buffer对象与字符串直接相互

Node.js安装教程--windows中通过安装nvmw方式安装管理node

领导找谈话,公司不好混了,说要想清楚以后发展方向啥的.就想想研究下node.js吧. 首先在知乎上看看介绍,大体了解了node.js ,百度搜索确实很多乱七八糟的,感觉还是知乎靠谱点.附上知乎的node.js的话题地址:https://www.zhihu.com/topic/19569535 然后随即找了个新手教程:http://www.runoob.com/nodejs/nodejs-install-setup.html  照着做很简单的就安装好node了.然后接着找找资料看,由于我是自己研究

【Node.js 学习二】 NPM的使用

NPM是随同Node.js一起安装的包管理工具,能解决NOdeJs代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器中下载别人编写的第三方包到本地使用 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用 允许用户将自己编写的包或者命令行程序上传到NPM服务器供别人使用 由于新版的NodeJs已经集成了NPM,所以之前npm也一并安装好了,同样可以通过输入"npm -v"来测试是否安装成功.命令如下,显示出版本号则表示安装成功. //Windows环境下

Node.js压缩web项目中的js,css和图片

安装node.js 这个非常简单,下载下来,配置下环境变量就可以了,使用node -v查看是否安装成功 安装压缩需要的模块分别是uglify-js,clean-css,node-smushit 命令是npm install xxx ,我之前安装都是不适于全局安装的,这个应该无所谓 编写压缩的js(应该很好看懂) /*******压缩JS******/ var fs = require('fs'); var uglify = require("../../nodejs/node_modules/u

清晰地去看 Node.js(二)

比较缓冲器拷贝缓冲区 路由指的就是我们要针对不同的URL有不同的处理方式,例如处理/start的业务逻辑和处理/upload模块 的业务:逻辑就 是不一致的. Node.js 模块系统:http://www.shouce.ren/api/view/a/3470 代码区: /** * 比较缓冲器 * buf1.compare(buf2); */ var buffer1 = new Buffer('ABC'); var buffer2 = new Buffer('ABCD'); var result