문제

nodejs에서는 실제로 차단 I/O 작업이 없습니다. 이는 거의 모든 NodeJS IO 코드에 많은 콜백이 포함되어 있음을 의미합니다. 이것은 데이터베이스, 파일, 프로세스 등의 읽기 및 쓰기에 적용됩니다. 이에 대한 일반적인 예는 다음과 같습니다.

var useFile = function(filename,callback){
    posix.stat(filename).addCallback(function (stats) {
        posix.open(filename, process.O_RDONLY, 0666).addCallback(function (fd) {
            posix.read(fd, stats.size, 0).addCallback(function(contents){
                callback(contents);
            });
        });
    });
};

...

useFile("test.data",function(data){
    // use data..
});

나는 작성 코드를 작성하고 있습니다 많은 IO 운영이므로 글을 쓸 것으로 기대합니다 많은 콜백. 콜백을 사용하는 것이 매우 편하지만 모든 재귀가 걱정됩니다. 나는 너무 많은 재귀에 빠지고 어딘가에 스택을 통해 불고있을 위험이 있습니까? 수천 개의 콜백을 통해 수천 명의 개인 글을 내 키 가치 상점에 만들면 결국 내 프로그램이 충돌할까요?

영향을 오해하거나 과소 평가하고 있습니까? 그렇지 않다면 여전히 Nodejs의 콜백 코딩 스타일을 사용하는 동안이 문제를 해결할 수있는 방법이 있습니까?

도움이 되었습니까?

해결책

당신이 보여주는 코드 중 어느 것도 재귀를 사용하지 않습니다. 전화 할 때 useFile 전화 posix.stat(), 반환 및 useFile 완료로 실행되면 종료됩니다. 나중에 전화 할 때 posix.stat() 완료되었습니다 기본 시스템 내에서 결과를 사용할 수 있으며, 추가 할 콜백 기능이 실행됩니다. 그 전화 posix.open(), 완료로 실행되면서 종료됩니다. 파일이 성공적으로 열리면 콜백 함수가 저것 실행, 전화 posix.read(), 그런 다음 그대로 끝나고 완성되었습니다. 마지막으로, 읽기 결과를 사용할 수 있으면 가장 안쪽 함수가 실행됩니다.

중요한 점은 각 기능이 posix.*() 함수는 차단하지 않습니다. 즉, 즉시 돌아와서 기본 시스템에서 마법이 시작되었습니다. 따라서 각 기능은 종료되며 나중에 이벤트는 다음 기능이 실행됩니다. 그러나 어떤 시점에도 재귀도 없습니다.

코드의 중첩 구조는 외부의 물건이 자체 엔드 포인트에 도달하기 전에 내부의 물건이 마무리해야한다는 인상을 줄 수 있습니다. 그러나 이러한 스타일의 비동기 이벤트 중심 프로그래밍에서 DEEPRER => wather-later-wans.

편집 : 각 중첩 된 함수가 끝나기 직전에 로깅 진술을 추가하십시오. 이것은 그들이 완료 한 순서가 외부 내부에서 나온다는 것을 설명하는 데 도움이 될 것입니다.

다른 팁

디버그 출력이 추가 된 동일한 예제 (출력은 아래 참조) :

usefile.js :

var sys = require("sys"),
  posix = require("posix");

var useFile = function(filename,callback){
    posix.stat(filename).addCallback(function (stats) {
        posix.open(filename, process.O_RDONLY, 0666).addCallback(function (fd) {
            posix.read(fd, stats.size, 0).addCallback(function(contents){
                callback(contents);
                sys.debug("useFile callback returned");
            });
            sys.debug("read returned");
        });
        sys.debug("open returned");
    });
    sys.debug("stat returned");
};

useFile("usefile.js",function(){});

산출:

DEBUG: stat returned
DEBUG: open returned
DEBUG: read returned
DEBUG: useFile callback returned

당신은 시도 할 수 있습니다

http://github.com/creationix/do

또는 내가했던 것처럼 자신을 굴립니다. 지금은 오류 처리가 누락 된 것을 신경 쓰지 마십시오 (그냥 무시하십시오);)

var sys = require('sys');

var Simplifier = exports.Simplifier = function() {}

Simplifier.prototype.execute = function(context, functions, finalFunction) {
  this.functions = functions;
  this.results = {};
  this.finalFunction = finalFunction;
  this.totalNumberOfCallbacks = 0
  this.context = context;
  var self = this;

  functions.forEach(function(f) {
    f(function() {
      self.totalNumberOfCallbacks = self.totalNumberOfCallbacks + 1;
      self.results[f] = Array.prototype.slice.call(arguments, 0);     
      if(self.totalNumberOfCallbacks >= self.functions.length) {
        // Order the results by the calling order of the functions
        var finalResults = [];
        self.functions.forEach(function(f) {
          finalResults.push(self.results[f][0]);
        })
        // Call the final function passing back all the collected results in the right order 
        finalFunction.apply(self.context, finalResults);
      }
    });
  });
}

그리고 그것을 사용하는 간단한 예

// Execute 
new simplifier.Simplifier().execute(
  // Context of execution
  self,  
  // Array of processes to execute before doing final handling
  [function(callback) {
      db.collection('githubusers', function(err, collection) {
        collection.find({}, {limit:30}, function(err, cursor) {
          cursor.toArray(function(err, users) { callback(users); })
        });
      });      
    },

    function(callback) {
      db.collection('githubprojects', function(err, collection) {
        collection.find({}, {limit:45, sort:[['watchers', -1]]}, function(err, cursor) {
          cursor.toArray(function(err, projects) { callback(projects); })
        });
      });              
    }
  ],  
  // Handle the final result
  function(users, projects) {
    // Do something when ready
  }
);

당신의 물건은 괜찮습니다. 나는 HTTP 리디렉션을 따르기 위해 Express에서 재귀적인 호출을하지만, 당신의 행동은 "트래버스"이며 재귀가 아닙니다.

또한 '단계'를 살펴보십시오 (http://github.com/creationix/step) 또는 github의 'flow-js'. 이렇게하면 더 자연스러운 스타일로 콜백 흐름을 쓸 수 있습니다. 이것은 또한 재귀가 없다는 것을 분명히 할 것입니다.

모든 JavaScript와 마찬가지로 Node.js와 함께 재귀 호출을 할 수 있습니다. 재귀 깊이 문제가 발생하면 (Nickfitz가 지적했듯이, 위험하지 않은 것 같습니다), 종종 코드를 다시 작성하여 대신 간격 타이머를 사용 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top