Node异步编程解决方案

前言

Node得益于自身的异步非阻塞I/O展现出的优秀性能而大力发展。但是异步I/O也带来相应的一系列问题,回调地狱、递归嵌套。。。被人们所诟病,本文记录一些异步解决方案,使Node的并行I/O处理得到更好的利用

解决方案

主要解决方案有如下几种:

  1. 发布/订阅模式
  2. Promise/Deferred模式
  3. 事件控制库

发布订阅模式

发布订阅模式是设计模式的一种,在JavaScript中可以利用回调的形式,将不变与变化部分得到解耦,只需关心具体的业务过程,而不需要关心中间处理。Javascript发布订阅模式,Node中events模块原生实现发布订阅模式

const events = require("events");
const fs = require("fs");

const emitter = new events.EventEmitter();
emitter.on("read_foo",function(err,data){
  console.log(data);
})

fs.readFile("./profile.jpg",function(err,data){
  return emitter.emit("read_foo",err,data);
})

对同一事件超出10个监听器会造成内存泄漏问题,会得到警告,另外,EventEmitter为了处理error事件,发生错误时会检测是否有error事件监听器,如果存在会将错误交给监听器处理。通过util的模块可以轻松继承EventEmitter

const events = require("events");
const util = require("util");

function Events(){
  return events.EventEmitter.call(this);
}
util.inherits(Events,events.EventEmitter);

偏函数

偏函数是通过判断执行次数来判断是否执行函数的功能函数

const after = function(times,callback){
  let result = {},count = 0;
  return function(key,value){
    result[key] = value;
    if(++count===times){
      return callback(result);
    }
  }
}

根据这个性质,可以利用偏函数利用Node的异步I/O性能处理,先看一个没有利用偏函数的异步处理过程(常见的回调地狱过程)

fs.readdir(path.join(__dirname,".."),function(err,files){
  files.forEach(function(filename,index){
    fs.readFile(filename,"utf-8",function(err,file){
      // TODO
    })
  })
})

上述代码常见于Node中,常见的完成任务即可的代码,上述代码完全没有利用到Node的优势异步I/O,将其变为串行处理,而Node的优势在于处理如下过程进行并行处理

fs.readdir(path.join(__dirname,".."),function(err,files){})
fs.readFile("./profile.jpg","utf-8",function(err,data){})
fs.readFile("./sun.jpg","utf-8",function(err,data){})

添加偏函数处理

const fs = require("fs");
const path = require("path");
const events = require("events");

const emitter = new events.EventEmitter();
const after = function(times,callback){
  let result = {},count = 0;
  return function(key,value){
    result[key] = value;
    if(++count===times){
      return callback(result);
    }
  }
}
const done = after(3,function(res){
  console.log(res)
})
emitter.on("done",done);

fs.readdir(path.join(__dirname,".."),function(err,files){
  emitter.emit("done","data1",files);
})
fs.readFile("./profile.jpg","utf-8",function(err,data){
  emitter.emit("done","data2",data);
})
fs.readFile("./sun.jpg","utf-8",function(err,data){
  emitter.emit("done","data3",data);
})

Promise/Deferred模式

发布了85 篇原创文章 · 获赞 62 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_36754767/article/details/105241844