Node.js系列--异步流程控制

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">	</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">异步编程是Node.js中最大的特点,在Node.js的编程实践中我们为了使得其发挥特性,将所有的东西都写成异步方式,特别是异步回调方式。在Node.js原生代码中,只有fs模块即提供了同步版本又提供了异步版本。现在我们来认识一下Node.js的异步流程控制。</span>

一、 callback

在Node.js中,无论是自定义API还是原生方法到处都可以看到callback的身影,说道callback就要说说Node.js的异步编程机制了,Node.js是一个底层由C++扩展的javascript运行时环境,它使得javascript可以在浏览器沙箱之外运行。由于javascript大多数时候(被熟知的)是运行在浏览器里面,用于提升页面交互性,制作特效等的脚本语言,本身不具备太多操作文件,操作系统资源的能力,这些都是通过C++扩展的,并且用google鼎鼎大名的V8引擎来执行javascript代码。javascript程序在执行的时候是单线程的,就是一段代码无法被分割到多个线程执行,然后在对结果进行归一处理。但是在浏览器中整个javascript的runtime不是单线程的,因为浏览器能够通过创建多线程执行多个javascript程序,比如ajax,在浏览器中ajax并不会阻塞当前的页面的其它javascript代码的执行,因为两者是独立运行的,服务器返回结果再由浏览器通过ajax对象将数据导入javascript的runtime当中。在javascript中异步编程,即在执行某个处理函数的时候,并没有等待执行结果,而是任务调度器将程序的控制权交给了其它处理逻辑,当之前的处理完成后再将程序的控制权交还给那个逻辑,这样就有了javascript中的“当....则...."这样的异步回调逻辑。

//浏览器总ajax异步回调的例子
//1. ajax请求/hello
//2. 当请求得到响应则输出结果
$.get('/hello', function(data){
     console.log(data)
})
</pre><pre name="code" class="javascript">//node.js中异步回调的例子
var fs = require('fs');
fs.readFile('hello.txt', function(error, text){
    if(error) throw error;
    console.log(text);
})


上面的示例就是典型的异步回调的例子,我们用匿名的function函数作为callback参数


// 自定义函数

functiton myReadFile(file, enc, callback){
    fs.readFile(file, enc, function(error, data){

       if(error){

       return callback(error);

       }
return callback(null, data); 

   })
}


上面的例子是我们自己定义的函数,同样 的在调用的时候也是一样的要传入callback参数,接收函数的处理结果。
        

二、async

这里的async只是列举了一个例子,他并不是一种编程范式,而是一个工具集合,它同样使用的是callback方式,但是它能让我们的程序的流程更加的清晰,可控制。这个是主要的,特别是很好的解决了异步回调的深层嵌套问题, 它提供了很多的方法,包括对map的处理。在编写Node.js程序时所要用到的流程控制几乎都已经涉及到了,这里简单的举个例子,更多的可以查看npm网站async文档。

var async = require('async')

async.map(fileList, function(file, callback){
    var stream = fs.createReadStream(file.filePath);
    (oss.ossClient).putObject({
        bucket: bucket,
        object: file.objectPath,
        srcFile: stream,
        contentType:file.contentType,
        contentLength: file.length
    }, function (uploadOssError, result) {
        //上传执行完成无论成功与否均需删除本地文件
        fs.unlink(file.filePath, function(unLinkError1){
            if (unLinkError1){
                console.log('传输完成,文件删除失败');
            }
            if(uploadOssError || result.statusCode !== 200){
                //console.log('文件上传至oss失败');
                console.log(uploadOssError.message);
                return callback(uploadOssError || new Error('upload file to oss fail.'));
            }
        });
        //传输完成的文件需要删除
        return callback(null);
    });
},function(error){
    if(error){
        return next(error);
    }
    req.oss = ossPath;
    //需要将上传的信息传到下一个中间件
    return next(null);
});

三、promise

promise 是避免callback的编程实践, 但是它所带来的不仅仅是避免callback,以及callback造成的嵌套过深的问题,更多的是为了解决Node.js或者说是javascript异步编程中的代码可靠性问题,因为深层嵌套只是一个表面的问题。其深层是所隐含的问题是代码缺乏可控性和可靠性。

        promise也是本文要着重讲的内容。Promise A+ 规范: https://promisesaplus.com/ 

        关于promise的实现,各不相同,但是按照Promise 规范实现的就是Promise, 关于Promise的感念,原理大概是这样的:

        某一个处理都是一个promise, 这个任务有pending(表示正在发生), fulfilled(表示已经履行),rejected(表示被拒绝)三种状态,这个任务的执行将对其状态产生影响,其状态也会相应的发生改变。但是最终状态必然是fulfilled或者rejected二者之一。fulfilled表示成功,rejected表示失败。而且任务的状态不可能从fulfilled变成rejected或者pending, 也不可能从rejectd变成fulfilled或者pending。这就保证了逻辑处理的可靠性。从变成形式来看。不同的状态对应着不同的处理函数。对错误的处理也比较统一,具备一致性。下面具体讲一下在编程中的使用。

1. Promise是一个对象,包含了其状态,以及相应状态的处理方法。

2. 使用then方法并接收两个参数(fulfilled, rejected)对应着逻辑处理结果

3. then返回一个新的Promise对象。

4. then的返回是新的Promise对象,所以形成一个Promise链,从而可以进行链式操作。

Promise规范中定义的东西差不多就是这些,但是可以在此基础上对编程过程中常见的一些使用场景进行扩展,包括了对不同逻辑的支持,特别是并行任务,上下关联任务等等。在Node.js的Promise系列0模块中,比较知名的就是Q,是一个标准的Promise实现。还提供了很多比较有用的方法。下一篇我们就来详细讲解一下这个模块,以及所提供的方法及其用法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值