NodeJS的Promise的用法解析


Posted in NodeJs onMay 05, 2016

Javascript的特点是异步,Javascript不能等待,如果你实现某件需要等待的事情,你不能停在那里一直等待结果回来,相反,底线是使用回调callback:你定义一个函数,这个函数只有等到结果可用时才能被调用。

这种回调模型对于好的代码组织是没有问题的,但是也可以通过从原始回调切换到promise解决很多问题,将promise看成是一个标准的数据容器,这样会简化你的代码组织,可以成为基于promise的架构。

什么是Promise?

一个promise是一个带有".then()"方法的对象,其代表的是一个操作的结果可能还没有或不知道,无论谁访问这个对象,都能够使用".then()"方法加入回调等待操作出现成功结果或失败时的提醒通知,。

那么为什么这样做好处优于回调呢?标准的回调模式在我们处理请求时需要同时提供回调函数:

request(url, function(error, response) { 

 // handle success or error.

});

doSomethingElse();

很不幸,这段代码意味着这个request函数并不知道它自己什么时候能够完成,当然也没有必要,我们最终通过回调传递结果。这会导致多个回调形成了嵌套回调,或者称为回调陷阱。

queryTheDatabase(query, function(error, result) { 

 request(url, function(error, response) {

  doSomethingElse(response, function(error, result) {

   doAnotherThing(result, function(error, result) {

    request(anotherUrl, function(error, response) {

     ...

    });

   });

  });

 });

});

Promise能够解决这种问题,允许低层代码创建一个request然后返回一个对象,其代表着未完成的操作,让调用者去决定应该加入什么回调。

Promise是什么?

promise是一个异步编程的抽象,它是一个返回值或抛出exception的代理对象,一般promise对象都有一个then方法,这个then方法是我们如何获得返回值(成功实现承诺的结果值,称为fulfillment)或抛出exception(拒绝承诺的理由,称为rejection),then是用两个可选的回调作为参数,我们可以称为onFulfilled和OnRejected:

var promise = doSomethingAync()
promise.then(onFulfilled, onRejected)

当这个promise被解决了,也就是异步过程完成后,onFulfilled和OnRejected中任何一个将被调用,

因此,一个promise有下面三个不同状态:

■pending待承诺 - promise初始状态
■fulfilled实现承诺 - 一个承诺成功实现状态
■rejected拒绝承诺 - 一个承诺失败的状态

以读取文件为案例,下面是使用回调实现读取文件后应该做什么事情(输出打印):

readFile(function (err, data) {

 if (err) return console.error(err)

 console.log(data)

})

如果我们的readFile函数返回一个promise,那么我们可以如下实现同样的逻辑(输出打印):

var promise = readFile()
promise.then(console.log, console.error)

这里我们有了一个值promise代表的是异步操作,我们能够一直传递这个值promise,任何人访问这个值都能够使用then来消费使用它,无论这个值代表的异步操作是否完成或没有完成,我们也能保证异步的结果不会改变,因为这个promise代表的异步操作只会执行一次,状态是要么fulfilled要么是rejected。

理解Promise

Promise可能是不同于日常直觉,为了理解它,一些重要原理必须记牢: .then()总是返回一个新的promise.,如下面代码:

var promise = readFile()
var promise2 = promise.then(readAnotherFile, console.error)

这里then的参数readAnotherFile, console.error是代表异步操作成功后的动作onFulfilled或失败后的动作OnRejected,也就是说,读取文件成功后执行readAnotherFile函数,否则失败打印记录错误。这种实现是两个中只有一种可能。

我们再看下面上述代码如下:

var promise = readFile()

var promise2 = promise.then(function (data) {

 return readAnotherFile() // 如果readFile成功,执行readAnotherFile

}, function (err) {

 console.error(err) // 如果readFile不成功,记录,但是还是执行readAnotherFile

 return readAnotherFile()

})

promise2.then(console.log, console.error) // readAnotherFile函数的执行结果

因为then返回一个promise,它意味着promise能够被chain串行链条花,这样能避免回调地狱:

readFile()

 .then(readAnotherFile)

 .then(doSomethingElse)

 .then(...)

Promise法则有两部分必须分离:

(1).then()总是返回一个新的promise,每次你调用它,它不管回调做什么,因为.then()在回调被调用之前已经给了你一个承诺promise,回调的行为只影响承诺promise的实施,如果回调返回一个值,那么promise将使用那个值,如果这个值是一个promise,返回这个promise实施后的值给这个值,如果回调抛出错误,promise将拒绝错误。

(2)被.then()返回的promise是一个新的promise,它不同于那些.then()被调用的promise,promise长长的链条有时会好些隐藏这个事实,不管如何,每次.then()调用都会产生一个新的promise,这里必须注意的是你真正需要考虑的是你最后调用.then()可能代表失败,那么如果你不捕获这种失败,那么容易导致你的错误exception消失。

一些人认为.then()串联链条调用很类似fluent风格,但是长长的promise链条会让人迷惑,最后切分为一个个有意义的函数:

function getTasks() { 

 return $http.get('http://example.com/api/v1/tasks')

  .then(function(response) {

   return response.data;

  });

}

 

function getMyTasks() { 

 return getTasks()

  .then(function(tasks) {

   return filterTasks(tasks, {

    owner: user.username

   });

  });

}

在这个例子中,两个函数各自获得一个promise,携带了一个回调函数。

有趣的Promise

同样的promise能够接受任何数目的回调,当一个Promise被解决实施后,其中所有回调函数都会被调用,此外,一个promise在被解决实施后,甚至可以接受一个新的回调,这些回调完成能以正常方式被调用,这就允许我们使用回调实现简单形式的缓存:

var tasksPromise; 

function getTasks() { 

 taskPromise = taskPromise || getTasksFromTheServer();

 return taskPromise;

}

这个案例中,getTasks()函数可以被任意次数调用,它总是返回铜牙的promise,其中函数getTasksFromTheServer()却只是被调用一次。

以上这篇NodeJS的Promise的用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
NodeJS学习笔记之网络编程
Aug 03 NodeJs
Ajax异步文件上传与NodeJS express服务端处理
Apr 01 NodeJs
nodejs个人博客开发第五步 分配数据
Apr 12 NodeJs
nodejs 终端打印进度条实例代码
Apr 22 NodeJs
nodejs集成sqlite使用示例
Jun 05 NodeJs
原生nodejs使用websocket代码分享
Apr 07 NodeJs
详解nodejs通过响应回写的方式渲染页面资源
Apr 07 NodeJs
nodejs异步编程基础之回调函数用法分析
Dec 26 NodeJs
nodejs语言实现验证码生成功能的示例代码
Oct 13 NodeJs
nodejs各种姿势断点调试的方法
Jun 18 NodeJs
ubuntu系统下使用pm2设置nodejs开机自启动的方法
May 12 NodeJs
浅谈JS和Nodejs中的事件驱动
May 05 NodeJs
Windows 系统下设置Nodejs NPM全局路径
Apr 26 #NodeJs
Nodejs Stream 数据流使用手册
Apr 17 #NodeJs
NodeJS创建基础应用并应用模板引擎
Apr 12 #NodeJs
nodeJs爬虫获取数据简单实现代码
Mar 29 #NodeJs
Nodejs如何搭建Web服务器
Mar 28 #NodeJs
Nodejs中的this详解
Mar 26 #NodeJs
快速掌握Node.js之Window下配置NodeJs环境
Mar 21 #NodeJs
You might like
通过缓存数据库结果提高PHP性能的原理介绍
2012/09/05 PHP
Apache下禁止php文件被直接访问的解决方案
2013/04/25 PHP
yii框架builder、update、delete使用方法
2014/04/30 PHP
php去除二维数组的重复项方法
2015/11/03 PHP
PHP使用PDO调用mssql存储过程的方法示例
2017/10/07 PHP
一段利用WSH获取登录时间的jscript代码
2008/05/11 Javascript
js+CSS 图片等比缩小并垂直居中实现代码
2008/12/01 Javascript
JavaScript 大数据相加的问题
2011/08/03 Javascript
jquery获取iframe中的dom对象(两种方法)
2013/07/02 Javascript
Jquery增加鼠标中间功能mousewheel的实例代码
2013/09/05 Javascript
编写js扩展方法判断一个数组中是否包含某个元素
2013/11/08 Javascript
关于JS 预解释的相关理解
2016/06/28 Javascript
js 将input框中的输入自动转化成半角大写(税号输入框)
2017/02/16 Javascript
vue不通过路由直接获取url中参数的方法示例
2017/08/24 Javascript
javascript input输入框模糊提示功能的实现
2017/09/25 Javascript
Bootstrap 树控件使用经验分享(图文解说)
2017/11/06 Javascript
微信小程序如何修改本地缓存key中单个数据的详解
2019/04/26 Javascript
优化Vue项目编译文件大小的方法步骤
2019/05/27 Javascript
vue实现鼠标移过出现下拉二级菜单功能
2019/12/12 Javascript
[27:02]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第三场
2014/05/24 DOTA
[10:21]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster 选手采访
2021/03/11 DOTA
python实现dict版图遍历示例
2014/02/19 Python
matplotlib调整子图间距,调整整体空白的方法
2018/08/03 Python
cProfile Python性能分析工具使用详解
2019/07/22 Python
python matplotlib 绘图 和 dpi对应关系详解
2020/03/14 Python
通过css3动画和opacity透明度实现呼吸灯效果
2019/08/09 HTML / CSS
HTML5+CSS设置浮动却没有动反而在中间且错行的问题
2020/05/26 HTML / CSS
NYX Professional Makeup官方网站:专业彩妆和美容产品
2019/10/29 全球购物
Nobody Denim官网:购买高级女士牛仔裤
2021/03/15 全球购物
某公司.Net方向面试题
2014/04/24 面试题
初中升旗仪式演讲稿
2014/05/08 职场文书
美国留学经济担保书
2014/05/20 职场文书
党员批评与自我批评思想汇报(集锦)
2014/09/14 职场文书
2015中学学校工作总结
2015/07/20 职场文书
高中开学感言
2015/08/01 职场文书
社会实践心得体会范文
2016/01/14 职场文书