2014-12-10 3 views
0

최근에 Node JS in Action 책을 읽음으로써 node.js를 학습하기 시작했습니다. 이것은 아마도 초보자 질문이지만 콜백 함수와 javascript 범위의 여러 게시물을 읽은 후에도이 코드의 제 5 장에있는 아이디어를 이해하는 데 여전히 문제가 있습니다.Node.js 콜백 내 콜백 함수 호출

function loadOrInitializeTaskArray(file, cb) { 
    fs.exists(file, function(exists) { 
    var tasks = []; 
    if (exists) { 
     fs.readFile(file, 'utf8', function(err, data) { 
     if (err) throw err; 
     var data = data.toString(); 
     var tasks = JSON.parse(data || '[]'); 
     cb(tasks); 
     }); 
    } else { 
     cb([]); 
    } 
    }); 
} 

function listTasks(file) { 
    loadOrInitializeTaskArray(file, function(tasks) { 
    for(var i in tasks) { 
     console.log(tasks[i]); 
    } 
    }); 
} 

두 콜백 함수가 두 개의 함수로 분리되어 있습니다. listTasks (..)가 먼저 호출되고 나중에 loadorInitializeTaskArray (..)를 호출합니다. 내 문제는 여기에서 시작됩니다.이 호출은 노드별로 어떻게 처리됩니까? loadOrInitializeTaskArray는 두 개의 인수를 취하고 두 번째 인수는 시그니처에 따라 매개 변수를 허용해서는 안되는 콜백 함수이지만 그럴 수 있습니다!
언제 cb (..)가 loadorInitializeTaskArray에서 호출되는지, 그게 무엇입니까 (도우미 함수를 호출하는 동일한 함수)입니까?

"tasks"는 function loadOrInitializeTaskArray에서 선언 된 배열입니다. listTasks (..) 함수에서 어떻게 액세스 할 수 있습니까?

자바 스크립트에서 변수의 범위는 정의 된 함수와 모든 중첩 된 함수 내에 있음을 알고 있습니다. 그러나 여기에서 그것을 이해하기가 힘듭니다. 누군가 여기서 일어나는 일을 설명 할 수 있습니까? 고맙습니다.

답변

3

합니다. 그래서, 그것으로 시작하자.
는 C, C++ ... 당신의 두뇌는이 같은이 코드를 해석하는 것 같은되는 언어의를 알고있는 경우의이 코드를

function foo(){ 
    var a = 3; 
    function bar(){ 
    console.log(a); 
    } 
    return bar; 
} 
var baz = foo(); 
baz(); // the value of a i.e 3 will appear on console 

를 생각해 보자. 당신이 그들 중 누구도 몰라 그냥 thiese 포인트를 무시하십시오.

    foo()가 호출
  • , a 변수 선언 foo가 파괴 될 함유 스택 리턴
  • 값 3을 할당한다. 그리고 따라서 a도 파괴 될 것입니다.
  • 그러면 세상에서 어떻게 baz()3을 출력하고 있습니까? ???

글쎄, 자바 스크립트에서 함수가 호출 될 때 일어나는 일은 C에서와 다릅니다. 그래서, 먼저 C 항목을 모두 읽은 후에 더 읽으십시오.

에서 자바 스크립트 범위 분석은 해당 코드의 "범위 내에있는"변수를 정의하는 객체 체인을 아래로 이동하여 수행됩니다. 어떻게 보죠?

  • 전역 JavaScript 변수를 선언 할 때 실제로 수행하는 작업은 전역 개체의 속성을 정의하는 것입니다.
  • 최상위 JavaScript 코드 (즉, 함수 정의에 포함되지 않은 코드)에서 범위 체인은 단일 개체 인 전역 개체로 구성됩니다.
  • 중첩되지 않은 함수에서 범위 체인은 두 개의 개체로 구성됩니다. 첫 번째는 함수의 매개 변수와 지역 변수를 정의하는 객체이고 두 번째는 전역 객체입니다.
  • 중첩 된 함수에서 범위 체인에는 세 개 이상의 개체가 있습니다. 함수가 정의되면 유효 범위 체인을 저장합니다. 이 함수가 호출되면 로컬 변수를 저장하는 새 객체를 만들고 해당 객체를 저장된 범위 체인에 추가하여 해당 함수 호출의 범위를 나타내는 새롭고 긴 체인을 만듭니다.

따라서 foo()이 실행될 때. 로컬 변수를 저장할 새 객체를 만듭니다. 따라서 변수 a이 해당 개체에 저장됩니다. 또한 막대가 정의됩니다. 막대가 정의되면 유효 범위 체인을 저장합니다. 따라서 막대의 범위 체인에는 변수 a이 들어있는 객체가 포함됩니다. 따라서 bar이 반환되면 스코프 체인에 대한 참조가 있습니다. 그리고 그러므로 그것은 a을 알고 있습니다.

그래서, 노드가 코드를 처리하는 방법에 대한 질문에 답할 것 같습니다.

당신이 쓴 :

loadOrInitializeTaskArray는 두 개의 인수를하고, 두 번째가에 따라 어떤 매개 변수를 허용하지 말아야 콜백 함수 서명이지만은 않습니다!

콜백 함수

function(tasks) { 
    for(var i in tasks) { 
     console.log(tasks[i]); 
    } 
} 

이며 인수 tasks을 받아 들인다. 그래서 여기 잘못 왔습니다.

loadOrIntializeTaskArray을 호출 할 때 cb는이 콜백 함수를 나타냅니다. 그리고 cb(arg) 기본적으로 수행합니다 tasks = arg 여기서 tasks는 콜백 함수의 인수입니다.

아직 많은 질문이있을 것입니다. 의견으로 알려주십시오. 그리고 노드로 들어가기 전에 Core Javascript를 사용하는 것이 좋습니다.

+1

Vishal에게 감사의 말을 전합니다. Javascript에 대한 타고난 지식이 부족하여 node.js를 학습하는 데 많은 영향을 미치는지 알지 못했습니다. 나는 오래 전에 클라이언트 측 자바 스크립트를 몇 개 만들었고 나는 잘되어야한다고 생각했다. 범위 지정, 종료와 같은 주제에 대해 중급/고급 javascript 가이드를 특별히 참조 할 수 있습니까? 그리고 당신은 맞습니다. 자바 언어에서 오는 노드에서의 코딩은 비동기식 콜백 모델과 혼동되고 있습니다. – Reza

+0

그래, 나는이 책을 좋아한다. [JavaScript : The Definitive Guide] (http://shop.oreilly.com/product/9780596805531.do). 그것은 정말 코어 및 클라이언트 사이드 자바 스크립트를위한 멋진 소스입니다. 노드를 시작하려면 코어 자바 스크립트를 읽어야합니다. – Vishal

0

"두 번째 것은 서명에 따라 매개 변수를 허용해서는 안되는 콜백 함수"라는 것이 확실하지 않습니다. 콜백 서명 (function(tasks))은 확실하게 인수 (tasks)를 기대합니다. .

cb

이 경우는 익명 함수 문자 그대로 전달 된 콜백 함수입니다 :

function(tasks) { 
    for(var i in tasks) { 
    console.log(tasks[i]); 
    } 
} 

tasks 두 개의 다른 변수의 이름은 (그러나 배열이기 때문에 그들은 동일한 개체를 가리 참조로 전달됨). 하나는 설명한대로 loadOrInitializeTaskArray()에 정의되어 있으며, 다른 하나는 loadOrInitializeTaskArray()에 전달 된 콜백 매개 변수입니다.

또한 관련없는 메모에서 일반적으로 콜백은 "오류 우선"형식을 따릅니다. 이를 통해 업스트림 오류를 처리 할 수 ​​있습니다. 이 규칙을 따르도록 코드를 수정하면 다음과 같은 결과가 발생합니다.

function loadOrInitializeTaskArray(file, cb) { 
    fs.exists(file, function(exists) { 
    var tasks = []; 
    if (exists) { 
     fs.readFile(file, 'utf8', function(err, data) { 
     if (err) 
      return cb(err); 

     var data = data.toString(); 

     // JSON.parse() throws errors/exceptions on parse errors 
     try { 
      var tasks = JSON.parse(data || '[]'); 
     } catch (ex) { 
      return cb(ex); 
     } 

     cb(null, tasks); 
     }); 
    } else { 
     cb(null, []); 
    } 
    }); 
} 

function listTasks(file) { 
    loadOrInitializeTaskArray(file, function(err, tasks) { 
    if (err) throw err; 
    for (var i in tasks) { 
     console.log(tasks[i]); 
    } 
    }); 
} 
+0

mscdex, 답장을 보내 주셔서 감사합니다. 자바 스크립트에 대한 나의 지식은 그렇게 깊지 않다. C++, Java 언어에서 함수 loadOrInitializeTaskArray (file, cb)와 같은 함수를 정의하면 배열 인수와 함께 loadOrInitializeTaskArray (file, function (TASKS))와 같이 호출 할 수 없습니다. 물론이 코드는 Javascript에 있습니다! – Reza

+0

그런 인라인 익명 함수를 사용하는 것이 일반적입니다. 함수를 꺼내 이름을 지정한 다음 함수 리터럴 대신 이름으로 같은 함수를 전달할 수 있습니다. Java/C++과의 언어 및 그 차이점에 더 익숙해 지려면 [MDN JavaScript Guide] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide)를 참조하십시오. – mscdex

0

처음에는 javascript에 함수 서명과 같은 것이 없습니다. 원하는만큼 함수에 인수를 전달할 수 있습니다. loadOrInitialiseTaskArray의 두 번째 인수는 함수가 호출 될 때 간단히 로컬 변수 cb에 할당됩니다. cb(tasks) 줄은이 값을 호출하므로 두 번째 인수가 더 나은 함수였습니다.

listTasks에서 loadOrInitializeTaskArray을 호출하면 두 번째 인수는 실제로 함수이며이 함수의 첫 번째 인수는 자체 범위에 tasks이라는 이름이 지정됩니다. loadOrInitializeTaskArray에 도달하지 않고 해당 함수의 범위에서 선언 된 변수를 사용하고 있습니다. cb을 호출 할 때 해당 값을 명시 적으로 전달했습니다.

코드는 우리가 변수 이름을 변경하면 이해하기 쉬울 아마도 동일하게 작동하고 것 : 당신은 정말 중첩 된 함수 내부 변수의 범위를 이해하는 데 어려움을 겪고있다

function loadOrInitializeTaskArray(file, cb) { 
    fs.exists(file, function(exists) { 
    var taskArray = []; 
    if (exists) { 
     fs.readFile(file, 'utf8', function(err, data) { 
     if (err) throw err; 
     var data = data.toString(); 
     var taskArray = JSON.parse(data || '[]'); 
     cb(taskArray); 
     }); 
    } else { 
     cb([]); 
    } 
    }); 
} 

function listTasks(file) { 
    loadOrInitializeTaskArray(file, function(listOfTasks) { 
    for(var i in listOfTasks) { 
     console.log(listOfTasks[i]); 
    } 
    }); 
} 
+0

신속한 답변을 부탁드립니다. 네, Javascript에서도 많은 경험이 없습니다. 부차적 인 질문으로, 우리가이 두 기능을 하나에 다시 쓰면 이해하기가 더 쉬울 것이라고 생각하지 않습니까? – Reza