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的require模块(文件模块/核心模块)及路径介绍
Jan 14 NodeJs
Nodejs学习笔记之入门篇
Apr 16 NodeJs
nodejs 中模拟实现 emmiter 自定义事件
Feb 22 NodeJs
NodeJs读取JSON文件格式化时的注意事项
Sep 25 NodeJs
nodejs实现发出蜂鸣声音(系统报警声)的方法
Jan 18 NodeJs
nodejs基础应用
Feb 03 NodeJs
初识NodeJS服务端开发入门(Express+MySQL)
Apr 07 NodeJs
使用koa-log4管理nodeJs日志笔记的使用方法
Nov 30 NodeJs
nodejs使用async模块同步执行的方法
Mar 02 NodeJs
nodejs npm错误Error:UNKNOWN:unknown error,mkdir 'D:\Develop\nodejs\node_global'at Error
Mar 02 NodeJs
Nodejs监听日志文件的变化的过程解析
Aug 04 NodeJs
NodeJS模块Buffer原理及使用方法解析
Nov 11 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
解析关于wamp启动是80端口被占用的问题
2013/06/21 PHP
Smarty中调用FCKeditor的方法
2014/10/27 PHP
PHP实现通过正则表达式替换回调的内容标签
2015/06/15 PHP
PHP智能识别收货地址信息实例
2019/01/05 PHP
PHP使用redis位图bitMap 实现签到功能
2019/10/08 PHP
通过JAVASCRIPT读取ASP设定的COOKIE
2007/02/15 Javascript
JavaScript 类型的包装对象(Typed Wrappers)
2011/10/27 Javascript
浅谈Javascript鼠标和滚轮事件
2012/06/27 Javascript
javascript回到顶部特效
2016/07/30 Javascript
微信小程序 swiper组件详解及实例代码
2016/10/25 Javascript
详解为Angular.js内置$http服务添加拦截器的方法
2016/12/20 Javascript
JS中微信小程序自定义底部弹出框
2016/12/22 Javascript
VUE中v-model和v-for指令详解
2017/06/23 Javascript
教你完全理解ReentrantLock重入锁
2019/06/03 Javascript
微信小程序登录对接Django后端实现JWT方式验证登录详解
2019/07/29 Javascript
vue+element-ui+axios实现图片上传
2019/08/20 Javascript
jQuery实现手风琴效果(蒙版)
2020/01/11 jQuery
vue 图片裁剪上传组件的实现
2020/11/12 Javascript
[01:10:03]OG vs EG 2018国际邀请赛淘汰赛BO3 第三场 8.23
2018/08/24 DOTA
Python列表list排列组合操作示例
2018/12/18 Python
Looking4Parking美国:全球排名第一的机场停车比较品牌
2019/08/26 全球购物
火山咖啡:Volcanica Coffee
2019/10/29 全球购物
巴西购物网站:Onofre Agora
2020/06/08 全球购物
英语专业学生的自我评价
2013/12/30 职场文书
美德好少年事迹材料
2014/01/19 职场文书
新员工入职感言
2014/02/01 职场文书
单位承诺书格式
2014/05/21 职场文书
好听的队名和口号
2014/06/09 职场文书
酒店总经理岗位职责范本
2014/08/08 职场文书
企业法人授权委托书
2014/09/25 职场文书
团党委领导干部党的群众路线教育实践活动个人对照检查材料思想汇
2014/10/05 职场文书
车间统计员岗位职责
2015/04/14 职场文书
幼儿园开学家长寄语(2016秋季)
2015/12/03 职场文书
Nginx代理同域名前后端分离项目的完整步骤
2021/03/31 Servers
浅谈Python3中datetime不同时区转换介绍与踩坑
2021/08/02 Python
简单聊聊Vue中的计算属性和属性侦听
2021/10/05 Vue.js