Node.js - promise


最开始想使用Node.js中的promise是基于以下的问题背景:
访问一个web服务器,向其发送post请求,获取相应的response,解析得到的response以后,根据其中的label编辑不同的post请求,再向另一个web服务器发送新的post请求,获得相应的response,流程图如下:

流程图.png

在没有使用promise时,由于Node.js的函数调用都是异步调用,要实现上述功能,就需要使用嵌套的函数回调,伪代码如下:

getLabel(URL1, function(error, result) {
    if(error) {
        throw error;
    } else {
        getRes1(URL2, function(error, result) {
            if(error) {
                throw error;
            } else {
                getRes2(URL2, function(error, result) {
                    if(error) {
                        throw error;
                    } else {
                        ......
                    }
                });
            }
        });
    }
});

显然,这样的写法是很不优雅的,有几个不同的label,就要几个回调函数,会使代码很冗长,而且很难维护,有没有简单明晰的方式能够完成这个任务呢?这个时候找到了promise。

Promise是什么,我的理解是promise其实也是一种回调,只是它给出了运行正常时的回调(通过resolve()到达),和运行错误时的回调(通过reject()到达),then()执行的就是将这两个回调连接起来。

每一个异步任务结束立刻返回一个promise对象,这个对象有一个then方法,允许调用指定的回调函数。某种程度上,这样的机制可以将若干异步的任务串行起来,使得前一个任务做完才能继续下一个任务。

这里不再赘述promise的原理和机制,promise的原理可以参照以下的链接,都讲解的很清楚:

接下来讲一下刚才的问题要如何通过promise来改写,先把代码贴出来:

/** Procedure 1
 *  Input : url of recognition website
 *  Output : recognition labels
**/
function GetLabel(url) {
    return new Promise(
    function (resolve, reject) {
        
        /*......*/
        
        fs.readFile(filepath, 'utf8', function (err, data){
            
            /*......*/
            
            var request = require('request');
            request(options, callback = 
                function (error, response, data) { 
                    if (!error && response.statusCode == 200) {
                        console.log('----info------', data);
                        resolve(data);
                    } else {
                        reject(error);
                    }
                });
        });
    }); 
}

/** Procedure 2
 *  Input : Feedback result of every iteration
 * 
 *  Output : Accumulated result
**/
function GetNutrition(param) {
    return new Promise(
    function (resolve, reject) {
        
        /*......*/
        
        var request = require('request');
        request(options, callback = 
            function (error, response, data) { 
                if (!error && response.statusCode == 200) {
                    console.log('----info------', data);
                    resolve(data);
                } else {
                    reject(error);
                }
            });
    });
}

/**
 *  Chain of the task
 */
GetLabel(URL1)
    .then(
        function (param) {
            console.log(param);
            return GetNutrition(param);
        })
    .then(
        function (param) {
            console.log(param);
            return GetNutrition(param);
        })
    .then(
        function (param) {
            console.log(param);
            return GetNutrition(param);
        })
    .then(function (param) {
            res.json({
                "result": jsonData.recommender
            });
        });

其中GetLabel()实现第一个任务,即取得URL1返回的label,成功以后将通过response得到的数据包直接返回给回调函数then(),并在then()中调用另一个promise GetNutrition(),通过这个promise回调下一个then()。其中的参数传递通过resolve()实现,代码中省去了catch。由此可以很好地将本来异步的实例串行化,也使得代码的结构更清晰一些。

下面有一个简单的小示例,用来总结这里介绍的promise的功能,代码如下:

var express = require('express');
var fs = require("fs");
var app = express();

/* has promise */
app.get('/', function (req, res) {
    res.send('Has Promise!');
    function SleepXSec (sec) {
        return new Promise(
        function (resolve, reject) {
            setTimeout(function() { console.log("+%s", sec); resolve(sec-5); }, sec*1000);
        }); 
    }
    SleepXSec(11)
        .then(function(sec) {
            return Sleep1Sec(sec);
        })
        .then(function(sec){
            return Sleep1Sec(sec);
        });
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

如果不使用promise,上述代码的结果应该是:

1s
6s
11s

但是由于使用了promise,强制确定了异步程序在上一个回调不结束之前不得进入下一步,因此输出变为:

11s
6s
1s

参考链接:

  1. http://nya.io/Node-js/promise-in-nodejs-get-rid-of-callback-hell/
  2. https://developers.google.com/web/fundamentals/getting-started/primers/promises?hl=zh-cn
  3. http://javascript.ruanyifeng.com/advanced/promise.html
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容