Promise是异步代码实现控制流的一种方式。这一方式可以让你的代码干净、可读并且健壮。

比如,你用来异步处理文件事件的回调代码:

  1. fs.readFile('directory/file-to-read', function(err, file){
  2. if (error){
  3. //handle error
  4. } else {
  5. //do something with the file
  6. }
  7. });

你以前可能听说过Node很快会陷入回调地狱,以上就是原因。作为一个node开发者你会遇到很多的异步代码,也就会遇到很多的回调(callback)。

这些回调还是比较简单的。但是你会需要在一个动作完成之后继续做别的动作,因此回调会不断的嵌套。你会发现很快这些代码就很难阅读了,更别提维护了。比如:

  1. fs.readFile('directory/file-to-read', function(err, file){
  2. if (error){
  3. //handle error
  4. } else {
  5. //do something with the file
  6. fs.mkdir('directory/new-directory', function(err, file){
  7. if (error) {
  8. //handle error
  9. } else {
  10. //new directory has been made
  11. fs.writeFile('directory/new-directory/message.txt', function(err, file){
  12. if(error) {
  13. // handle error
  14. } else {
  15. // File successfully created
  16. }
  17. });
  18. }
  19. });
  20. }
  21. });

在上面的例子中我想要异步的读取一个文件,然后创建一个目录并创建一个文件。你可以看到这个简单的三步走的任务变成了多么丑陋的嵌套的代码,尤其是一旦你再在这些代码中添加逻辑控制的时候,代码更是不可想象丑陋。

我们为什么要在node中使用Promise

以上面对的代码作为例子,我们将探究如何用Promise解决上面说到的问题:

  1. fs.readFileAsync('directory/file-to-read')
  2. .then(function(fileData){
  3. return fs.mkdirAsync('directory/new-directory');
  4. })
  5. .then(function(){
  6. return fs.writeFileAsync('directory/new-directory/message.txt');
  7. })

Promise给我们提供了一个更加清晰和健壮的方式编写异步代码。最开始的方法返回一个promise,这个promise上可以调用‘then’方法。‘then’之后还可以调用更多的‘then’。每个‘then’都可以访问上一个‘then’返回的信息。每一个‘then’方法返回的示例都可以再调用一个‘then’。这往往就是另一个异步的调用。

Promise也让你更加容易的把代码分解到多个文件中。比如:

  1. function readFileandMakeDirectory(){
  2. return fs.readFileAsync('directory/file-to-read')
  3. .then(function(fileData){
  4. return fs.mkdirAsync('directory/new-directory');
  5. });
  6. }
  7.  
  8. //The following will execute once the file has been read and a new directory has been made
  9. readFileandMakeDirectory()
  10. .then(function(){
  11. return fs.writeFileAsync('directory/new-directory/message.txt');
  12. })

很容易创建返回promise的方法。当你需要把代码分解到不同的文件中的时候会非常有用。比如,你可能有一个路由读取一个文件,读取其内容,并且把文章内容以json的形式返回出来。你可以把代码分解成多个返回promise的组件。

  1. //routes/index.js
  2. var router = require('express').Router();
  3. var getFileExcerpt = require('../utils/getFileExcerpt')
  4.  
  5. router.get('/', function(){
  6. getFileExcerpt.then(function(fileExcerpt){
  7. res.json({message: fileExcerpt});
  8. });
  9. });
  10.  
  11. module.exports = router;
  12.  
  13. //utils/getFileExcerpt.js
  14.  
  15. var Promise = require('bluebird');
  16. var fs = Promise.promisifyAll(require('fs'));
  17.  
  18. module.exports = function getPost(){
  19. return fs.readFileAsync(file, 'utf8').then(function(content){
  20. return {
  21. excerpt: content.substr(0, 100)
  22. }
  23. });
  24. }

以上代码也清楚的表明任何一个返回的‘then’后面可以再调用‘then’。

处理错误

使用promise处理错误非常简单。当执行一堆‘then’方法的过程中出现错误的时候Bluebird会找到最近的.catch方法执行。你可以在‘then’链中嵌入catch方法。上例可以改写为:

  1. fs.readFileAsync('directory/file-to-read')
  2. .then(function(fileData){
  3. return fs.mkdirAsync('directory/new-directory');
  4. })
  5. .then(function(){
  6. return fs.writeFileAsync('directory/new-directory/message.txt');
  7. })
  8. .catch(function(error){
  9. //do something with the error and handle it
  10. });

你可以使用catch处理错误。

但是我要用的模块不返回promise

你会注意到上面的例子中使用了‘fs.writeFileAsync'和’fs.mkdirAsync’。如果你检查node的文档你会看到这些方法并不存在。FS不会返回promise。

尽管如此,bluebird提供了一个非常有用的功能来promise化不返回promise的模块。比如,promise化fs模块,只需要简单地require bluebird模块和一个被promise化的fs模块。

  1. var Promise = require('bluebird');
  2. var fs = Promise.promisifyAll(require('fs'));

创建你自己的Promise

因为你可以promise化模块,所以你不会需要写很多的代码来创建promise。然后,即使如此知道如何创建也是很必要的。创建promise需要提供resolve和reject的回调方法。每一个都需要传对了:

  1. //myPromise.js
  2.  
  3. var Promise = require('bluebird');
  4.  
  5. module.exports = function(){
  6. return new Promise(function(resolve, reject){
  7. tradiationCallbackBasedThing(function(error, data){
  8. if (err) {
  9. reject(err);
  10. } else {
  11. resolve(data)
  12. }
  13. });
  14. });
  15. }

这样就完成了promise化。接下来,你就可以使用这个技术把你想要promise化的都写成promise的形式。

测试Promise

当我测试服务端代码的时候,我最喜欢的框架是mocha和chai。需要注意,测试异步代码的时候你需要告诉mocha异步代码什么时候执行完成。否则,他只会继续执行下面的测试,这时就会出错。

这个时候,只需要简单地调用mocha在it部分中提供的回调方法:

  1. it('should do something with some async code', function(done){
  2. readPost(__dirname + '/../fixtures/test-post.txt')
  3. .then(function(data){
  4. data.should.equal('some content inside the post');
  5. done();
  6. })
  7. .catch(done);
  8. });

Promise非常有用,使用node编写异步代码的时候强烈建议你使用promise。

可以通过阅读Bluebird的API文档了解更多。

Bluebird-NodeJs的Promise的更多相关文章

  1. Nodejs Q promise设计思路

    Nodejs Q promise库 前言 Q库为nodejs提供了一个基于promise的编程方式,从此避免了一层又一层的callback调用.不过Q的灵活性也给我造成了很大困扰,我可以用promis ...

  2. nodejs与Promise的思想碰撞

    玩node的同志们都知道,当这门语言被提出来的时候,作为自己最为骄傲的异步机制,却被PHP和Python等战团喷得不成样子的是,他们嘲笑着nodejs那蠢蠢的无限嵌套,nodejs战团只能以我们只要性 ...

  3. bluebird -1 New Promise方法

    new Promise new Promise(function(function resolve, function reject) resolver) -> Promise 创建一个Prom ...

  4. nodejs使用promise实现sleep

    个人博客 地址:http://www.wenhaofan.com/article/20181120180225 let sleep = function (delay) { return new Pr ...

  5. Nodejs Promise的一点记录

    项目需要,看了点nodejs,其中比较难理解的就是Promise了,记录一下学习bluebird提供的Promise实现. Promise.promisifyAll(obj)方法 作用:把对象的方法属 ...

  6. NodeJs回调操作Promise化

    mongoose是一个NodeJs下MongoDB的ORM库.使用这个库,您从DB到表(collection)都不用创建了.只需要在项目中定义好Model. 下面就是用上一篇的代码来演示如何把mong ...

  7. promise 进阶 —— async / await 结合 bluebird

    一.背景 1.Node.js 异步控制 在之前写的 callback vs async.js vs promise vs async / await 里,我介绍了 ES6 的 promise 和 ES ...

  8. 深入理解jQuery、Angular、node中的Promise

    最初遇到Promise是在jQuery中,在jQuery1.5版本中引入了Deferred Object,这个异步队列模块用于实现异步任务和回调函数的解耦.为ajax模块.队列模块.ready事件提供 ...

  9. q.js实现nodejs顺序调用

    nodejs的异步调用有时候是最让人头疼的,如何能是一些代码顺序的执行呢,这里和大家分享nodejs的promise 什么是promise promise一个标准,它描述了异步调用的返回结果,包括正确 ...

  10. 如何把函数都用promise方式实现?

    如何把函数都用promise方式实现? 我觉得这是一个好问题.当前在我所在的公司,只要用 NodeJS 进行开发,从框架到具体的应用实例到工具,已经全部迁移到以 promise 为中心开发方式.带来的 ...

随机推荐

  1. JAVA WEB开发中的资源国际化

    为什么要国际化? 不同国家与地区语言,文化,生活习惯等差异.在数字,时间,语言,货币,日期,百分数等的不同. 两个名词: I18N:即资源国际化,全称为Internationalization,因为首 ...

  2. AutoConfig工具使用

    下载安装Auto工具包: http://code.taobao.org/mvn/repository/com/alibaba/citrus/tool/antx-autoconfig/1.0.9/ant ...

  3. 罗伯特•盖洛博士(Dr. Robert Charles Gallo)是世界著名的美国生物医学家,他以共同发现了人类免疫缺陷病毒(HIV)――这一导致获得性免疫缺陷综合症(AIDS)的致病源而闻名于世。

    罗伯特•盖洛 开放分类:各国生物学家|生物学家罗伯特•盖洛博士(Dr. Robert Charles Gallo)是世界著名的美国生物医学家,他以共同发现了人类免疫缺陷病毒(HIV)――这一导致获得性 ...

  4. 基元线程同步构造 AutoResetEvent和ManualResetEvent 线程同步

    在.Net多线程编程中,AutoResetEvent和ManualResetEvent这两个类经常用到, 他们的用法很类似,但也有区别.ManualResetEvent和AutoResetEvent都 ...

  5. html资源 链接

    http://m.aicai.com/index.do?agentId=1&vt=5

  6. tesseract 4.0 编译安装(CentOS)

    1.安装依赖工具 yum install autoconf automake libtool libjpeg-devel libpng-devel libtiff-devel zlib-devel 2 ...

  7. Ansible介绍/安装/入门

    http://docs.ansible.com/ansible/ https://galaxy.ansible.com/ Ansible是一个IT自动化工具. 它可以配置系统,部署软件,并编排更先进的 ...

  8. electron 大体结构

    1.Electron支持的平台: OS XWindowsLinux 2.一个标准的electron app包含的结构: Windows 或是 Linux中:electron/resources/app ...

  9. pymongo的常用操作

    环境:pymongo3.0.3,python3 以下是我整理的一些关于pymongo的操作,网上很多是用pymongo.Connecion()去连接数据库的,但是我这里连接一直提示没有这个包,如果大家 ...

  10. 索引与like优化

    未建索引 mysql> alter table modulestatus drop index imei;Query OK, 457922 rows affected (4.29 sec)Rec ...