>  기사  >  웹 프론트엔드  >  노드 비동기 프로그래밍 메커니즘에 대한 자세한 설명

노드 비동기 프로그래밍 메커니즘에 대한 자세한 설명

小云云
小云云원래의
2018-01-09 17:17:371291검색

이 글은 주로 Node 비동기 프로그래밍의 메커니즘을 소개합니다. 편집자는 이것이 꽤 좋다고 생각합니다. 이제 여러분과 공유하고 참고하겠습니다. 편집자를 따라 살펴보겠습니다. 모두에게 도움이 되기를 바랍니다.

이 문서에서는 노드 비동기 프로그래밍을 소개하고 모든 사람과 공유합니다. 세부 사항은 다음과 같습니다.

현재 비동기 프로그래밍의 주요 솔루션은 다음과 같습니다.

  • 이벤트 게시/구독 모드

  • Promise/Deferred 모드

  • 프로세스 제어 라이브러리

이벤트 게시/구독 모드

노드 자체가 이벤트 모듈을 제공하여 이벤트 게시/구독을 쉽게 구현할 수 있습니다.


//订阅
emmiter.on("event1",function(message){
  console.log(message);
})
//发布
emmiter.emit("event1","I am mesaage!");

리스너를 유연하게 추가하고 삭제할 수 있습니다. 이벤트와 특정 처리 로직을 쉽게 연결하고 분리할 수 있습니다.

이벤트 게시/구독 모델은 비즈니스 로직을 분리하는 데 종종 사용됩니다. 이벤트 게시자는 구독하는 리스너가 비즈니스 로직을 구현하는 방법이나 심지어 리스너 수에 주의를 기울일 필요가 없습니다. 리스너가 존재하며, 메시지를 통해 유연하게 데이터를 전송할 수 있습니다.

다음 HTTP는 일반적인 애플리케이션 시나리오입니다


var req = http.request(options,function(res){
  res.on('data',function(chunk){
    console.log('Body:'+ chunk);
  })
  res.on('end',function(){
    //TODO
  })
})

이벤트에 리스너가 10명 이상 추가되면 emmite.setMaxListeners(0)

을 호출하여 이 제한을 제거할 수 있습니다. 이벤트 모듈 상속


var events = require('events');
function Stream(){
  events.EventEmiiter.call(this);
}
util.inherits(Stream,events.EventEmitter);

이벤트 큐를 사용하여 눈사태 문제 해결

소위 눈사태 문제는 높은 액세스 볼륨과 대규모 동시성 조건에서 캐시 오류가 발생하는 것입니다. 동시에 수많은 요청이 데이터베이스에 통합되면 데이터베이스는 동시에 이러한 대규모 쿼리 요청을 견딜 수 없으므로 웹사이트의 전체 응답 속도에 더욱 영향을 미칩니다. 다중 비동기 이벤트 사이의 솔루션


위의 상황은 리스너 간의 관계가 일대다이지만, 비동기 프로그래밍에서는 이벤트와 리스너 사이에 다대일 상황이 있을 수도 있습니다.


페이지를 예시로 렌더링하는 데 필요한 템플릿 읽기, 데이터 읽기, 현지화된 리소스 읽기에 대해 간략하게 소개합니다


var proxy = new events.EventEmitter();
var status = "ready"; 
var seletc = function(callback){
  proxy.once("selected",callback);//为每次请求订阅这个查询时间,推入事件回调函数队列
  if(status === 'ready'){ 
    status = 'pending';//设置状态为进行中以防止引起多次查询操作
    db.select("SQL",function(results){
      proxy.emit("selected",results); //查询操作完成后发布时间
      status = 'ready';//重新定义为已准备状态
    })
  }
}
부분 함수 체계


var count = 0 ;
var results = {};
var done = function(key,value){
  result[key] = value;
  count++;
  if(count === 3){
    render(results);
  }
}
fs.readFile(template_path,"utf8",function(err,template){
  done('template',template)
})
db.query(sql,function(err,data){
  done('data',data);
})
l10n.get(function(err,resources){
  done('resources',resources)
})

EventProxy 모듈 체계 소개

var after = function(times,callback){
  var count = 0, result = {};
  return function(key,value){
    results[key] = value;
    count++;
    if(count === times){
      callback(results);
    }
  }
}
var done = after(times,render);
var emitter = new events.Emitter();
emitter.on('done',done);  //一个侦听器
emitter.on('done',other);  //如果业务增长,可以完成多对多的方案

fs.readFile(template_path,"utf8",function(err,template){
  emitter.emit('done','template',template);
})
db.query(sql,function(err,data){
  emitter.emit('done','data',data);
})
l10n.get(function(err,resources){
  emitter.emit('done','resources',resources)
})

Promise/Deferred 모드

위 방식으로 이벤트를 사용할 경우 실행 프로세스를 미리 설정해야 하며 이는 게시/구독 모드의 작동 메커니즘에 따라 결정됩니다.

var proxy = new EventProxy();
proxy.all('template','data','resources',function(template,data,resources){
  //TODO
})
fs.readFile(template_path,'utf8',function(err,template){
  proxy.emit('template',template);
})
db.query(sql,function(err,data){
  proxy.emit('data',data);
})
l10n.get(function(err,resources){
  proxy.emit('resources',resources);
})

그럼 비동기 호출을 먼저 실행하고 전달 처리를 지연시키는 방법이 있나요? 다음으로 이야기할 것은 이 상황을 처리하는 방법입니다. Promise/Deferred 패턴

Promise/A

Promise/A는 단일 비동기 작업에 대해 다음과 같은 추상 정의를 제안합니다.


Promise 작업은 미완성, 완료, 실패의 세 가지 상태 중 하나에만 해당됩니다.

Promise 상태는 완료되지 않음에서 완료 또는 실패로만 변환되며, 완료됨 상태와 실패한 상태는 서로 변환될 수 없습니다.

Promise 상태가 변환되면 변경할 수 없습니다.
  • Promise 객체에는 then()만 있으면 됩니다
  • 완료 상태 및 오류 상태에서 콜백 메서드를 허용합니다.
  • 선택적으로 세 번째 메서드로 진행 이벤트 콜백을 지원합니다.

then() 메서드만 함수 개체를 허용하고 다른 개체는 무시됩니다
  • then() 메서드는 계속해서 Promise 개체를 반환하여 체인 호출을 구현합니다
  • Node의 이벤트 모듈을 통해 Promise 구현을 시뮬레이션합니다
  • $.get('/api',{
      success:onSuccess,
      err:onError,
      complete:onComplete
    })
    //需要严谨设置目标
  • 콜백 함수가 저장됩니다. then()을 통해, 다음 단계는 성공, 오류, 진행 이벤트가 트리거될 때까지 기다리는 것입니다. 이 함수를 구현한 객체를 지연 객체(Delay 객체)라고 합니다.
  • var Promise = function(){
      EventEmitter.call(this)
    }
    util.inherits(Promise,EventEmitter);
    
    Promise.prototype.then = function(fulfilledHandler,errHandler,progeressHandler){
      if(typeof fulfilledHandler === 'function'){
        this.once('success',fulfilledHandler); //实现监听对应事件
      }
      if(typeof errorHandler === 'function'){
        this.once('error',errorHandler)
      }
      if(typeof progressHandler === 'function'){
        this.on('progress',progressHandler);
      }
      return this;
    }
따라서 일반적인 응답 객체는


var Deferred = function(){
  this.state = 'unfulfilled';
  this.promise = new Promise();
}
Deferred.prototype.resolve = function(obj){ //当异步完成后可将resolve作为回调函数,触发相关事件
  this.state = 'fulfilled';
  this.promise.emit('success',obj);
}
Deferred.prototype.reject = function(err){
  this.state = 'failed';
  this.promise.emit('error',err);
}
Deferred.prototype.progress = function(data){
  this.promise.emit('progress',data)
}

로 캡슐화하여


res.setEncoding('utf8');
res.on('data',function(chunk){
  console.log("Body:" + chunk);
})
res.on('end',function(){
  //done
})
res.on('error',function(err){
  //error
}

로 변환할 수 있습니다. 위 변환을 완료하려면 먼저 res 객체, data, end, Error를 캡슐화해야 합니다. 및 기타 이벤트는 promisify


res.then(function(){
  //done
},function(err){
  //error
},function(chunk){
  console.log('Body:' + chunk);
})

위는 Deferred에 비즈니스의 불변 부분을 캡슐화하고 변수 부분을 Promise에 넘겨줍니다.

Promise의 다중 비동기 협업

var promisify = function(res){
  var deferred = new Deferred(); //创建一个延迟对象来在res的异步完成回调中发布相关事件
  var result = ''; //用来在progress中持续接收数据
  res.on('data',function(chunk){ //res的异步操作,回调中发布事件
    result += chunk;
    deferred.progress(chunk);
  })
  res.on('end',function(){    
    deferred.resolve(result);
  })
  res.on('error',function(err){
    deferred.reject(err);
  });
  return deferred.promise   //返回deferred.promise,让外界不能改变deferred的状态,只能让promise的then()方法去接收外界来侦听相关事件。
}

promisify(res).then(function(){
  //done
},function(err){
  //error
},function(chunk){
  console.log('Body:' + chunk);
})

Promise는 시퀀스를 지원합니다. 실행

코드를 변환하여 체인 호출을 구현해 보세요

Deferred.prototype.all = function(promises){
  var count = promises.length; //记录传进的promise的个数
  var that = this; //保存调用all的对象
  var results = [];//存放所有promise完成的结果
  promises.forEach(function(promise,i){//对promises逐个进行调用
    promise.then(function(data){//每个promise成功之后,存放结果到result中,count--,直到所有promise被处理完了,才出发deferred的resolve方法,发布事件,传递结果出去
      count--;
      result[i] = data;
      if(count === 0){
        that.resolve(results);
      }
    },function(err){
      that.reject(err);
    });
  });
  return this.promise; //返回promise来让外界侦听这个deferred发布的事件。
}

var promise1 = readFile('foo.txt','utf-8');//这里的文件读取已经经过promise化
var promise2 = readFile('bar.txt','utf-8');
var deferred = new Deferred();
deferred.all([promise1,promise2]).thne(function(results){//promise1和promise2的then方法在deferred内部的all方法所调用,用于同步所有的promise
  //TODO
},function(err){
  //TODO
})

관련 권장 사항:

Javascript의 비동기 프로그래밍 4가지 방법 소개

비동기 프로그래밍 설명 es6의 Promise


상세 자바스크립트 비동기 프로그래밍의 콜백 함수 및 관리자 사용 예에 ​​대한 설명

위 내용은 노드 비동기 프로그래밍 메커니즘에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.