2017-09-17 1 views
1

Google 드라이브 API를 통해 EJS 파일에 전달하는 파일 목록 (obj)을 전달하고 싶습니다.콜백 함수에서 app.get의 'response'매개 변수에 액세스하는 방법

즉 나는

app.get('/',function(req,res){ 
    res.render('index',obj); 
} 

문제는 내가 JS 몇 콜백 함수를 통해 객체를 얻고 있다는 것입니다 쓰고 싶어요. 이 기능은,

function processClientSecrets(err,content) { 
if (err) { 
    console.log('Error loading client secret file: ' + err); 
    return; 
}else{ 
    authorize(JSON.parse(content),findFiles); 
} 
} 

차례로 호출이 두 호출

fs.readFile('client_secret.json',processClientSecrets); 

라고

function authorise(credentials,callback) { 
var clientSecret = credentials.installed.client_secret; 
    var clientId = credentials.installed.client_id; 
    var redirectUrl = credentials.installed.redirect_uris[0]; 
    var auth = new googleAuth(); 
    var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); 

    // Check if we have previously stored a token. 
    fs.readFile(TOKEN_PATH, function(err, token) { 
    if (err) { 
     getNewToken(oauth2Client, callback); 
    } else { 
     oauth2Client.credentials = JSON.parse(token); 
     callback(oauth2Client); 
    } 
    }); 
} 

[편집]

function findFiles(auth){ 
var obj ={}; 
var key = 'files'; 
obj[key]=[]; 
var drive = google.drive('v3'); 
drive.files.list({ 
       auth: auth, 
       folderId: '****************', 
       q: "mimeType contains 'application/pdf' and trashed = false" 
       }, 
    function(err,response){ 
    var f = response.files; 
    if (f.length == 0) { 
    console.log('No files found.'); 
    }else { 
     var i; 
     for (i = 0; i < f.length; i++) { 
     var file = f[i]; 
     //console.log('%s (%s)', file.name, file.id); 
     obj[key].push(file.name + ' ' + file.id); 
     } 
     console.log(obj); 
     return obj; 
    } 
        }); 

} 

이것은처럼 보이는 아주 기본적인 질문 ,하지만 그것을 해결할 수 없다면 node.js는 본질적으로 비동기이며 obj를 반환하려는 모든 시도는 obj를 검색하기 전에 결과를 가져 왔습니다.

+0

컨트롤이 readFile에 도달 한 다음 권한 부여 (권한 부여에 의해 반환 된 객체를 기록 할 수 있음)로 이동하지만 그 이후에는 오류가 발생합니다. : – AlwaysHungrie

답변

1

콜백 오신 것을 환영합니다. :-) 예전의 "노드"방식은 중첩 된 콜백을 수행하는 것이고 매우 빠르게 발생합니다.

현대적인 접근 방식은 약속을 사용하여 여러 비동기 작업을 함께 구성하는 것이 더 쉽습니다. 자신의 비동기 함수가 약속을 반환하도록하고 Node API 함수 (또는 약속을 아직 제공하지 않는 애드온 라이브러리)의 경우 래퍼를 사용하여 약속 가능 (수동 또는 promisify과 같은 것을 사용)하도록 설정합니다. 약속 기반 기능

, 예를 들어, 전화는 다음과 같이 보일 것이다 :

app.get('/',function(req,res){ 
    readFilePromise('client_secret.json') 
     .then(content => JSON.parse(content)) 
     .then(authorise) 
     .then(findFiles) 
     .then(files => { 
      res.render('index', files); 
     }) 
     .catch(err => { 
      // Render error here 
     }); 
}); 

나부터도 JSON.parsefindFiles은 비동기 : 그것은 비 비동기를 사용하는 것이 괜찮

app.get('/',function(req,res){ 
    readFilePromise('client_secret.json') 
     .then(content => authorise(JSON.parse(content))) 
     .then(auth => { 
      res.render('index', findFiles(auth)); 
     }) 
     .catch(err => { 
      // Render error here 
     }); 
}); 

함수가 then 인 경우 함수가 하나의 매개 변수를 필요로하고 처리 된 결과를 반환하므로 비트가 이상인 경우에도 첫 번째 버전도 문제가되지 않습니다. 관련 머리. 두 경우 모두

readFilePromisereadFile의 promisified 버전이며, authorize이 같은 뭔가 같습니다!

function authorise(credentials) { 
    var clientSecret = credentials.installed.client_secret; 
    var clientId = credentials.installed.client_id; 
    var redirectUrl = credentials.installed.redirect_uris[0]; 
    var auth = new googleAuth(); 
    var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); 

    // Check if we have previously stored a token. 
    return readFilePromise(TOKEN_PATH) 
     .then(token => { 
      oauth2Client.credentials = JSON.parse(token); 
      return oauth2Client; 
     }); 
} 

(또한   — 주관 경고에 유의   —을 우리가 종료하지 않기 때문에 그 지옥이 깊게 중첩 된 콜백 구조를 사용하면 두 개의 공백보다 적절한 들여 쓰기 너비를 사용할 수 있으므로 많은 노드 프로그래머는 채택해야 할 필요성을 느끼게됩니다.

노드 V8을 사용하는 경우 앞으로 나아갑니다.X +, 당신은 그 약속을 소비 async/await 구문을 사용할 수 있습니다

app.get('/', async function(req, res){ 
    try { 
     const credentials = JSON.parse(await readFilePromise('client_secret.json')); 
     const auth = await authorize(credentials); 
     const files = findFiles(auth); 
     res.render('index', files); 
    } catch (e) { 
     // Render error here 
    } 
}); 

주에게 function 이전 asyncawait 언제든지 우리가 약속을 반환하는 함수를 호출하고 있습니다. async 함수는 커버 아래에 약속을 반환하고 await은 커버 아래에 약속을 사용합니다. 코드 동기식으로 보입니다. await은 사실상 then에 대한 호출이며 약속이 완료 될 때 콜백을 등록합니다. 마찬가지로 try/catch은 약속 체인에서 catch 메서드를 호출하는 것이 효율적입니다.

우리는 우리가 원한다면 것을 응축 수 :

app.get('/', async function(req, res){ 
    try { 
     res.render('index', findFiles(await authorize(JSON.parse(await readFilePromise('client_secret.json')))); 
    } catch (e) { 
     // Render error here 
    } 
}); 

...하지만 가독성/debuggability

고통. :-)

중요 사항 : (app.get를 같은) 약속을 반환하는 기능을 기대하지 않는 뭔가 내로 async 기능을 전달할 때, 당신은 로 위의 try/catch에 포장 및 오류를 처리해야합니다 왜냐하면 호출 코드가 약속을 기대하지 않는다면 약속 거부를 처리하지 않을 것이기 때문이다. 처리되지 않은 거부는 나쁜 것입니다 (노드의 이후 버전에서는 프로세스가 종료됩니다). 당신이 내로 async 기능을 전달하는 것은이 프로세스를 반환하는 함수를 기대하는 경우

, 최고의는 try/ catch`을 떠나 오류를 전파 할 수 있도록합니다.


findFiles와 관련하여 도움을 요청했습니다. 나는 promisify 또는 비슷한 것을 배우는 것이 좋습니다. 이 문제를 해결하는 올바른 방법은 내 생각에 drive.files.list의 약속 된 버전을 제공하는 것입니다. drive.files.list은 노드 스타일 콜백을 대신 사용하기 때문입니다.

그러나 그것을 promisifying하지 않고, 우리가 할 수있는 : 우리는 promisified 버전을 가지고 있다면

function findFiles(auth) { 
    var drive = google.drive('v3'); 
    return new Promise(function(resolve, reject) { 
     drive.files.list({ 
      auth: auth, 
      folderId: '****************', 
      q: "mimeType contains 'application/pdf' and trashed = false" 
     }, 
     function(err, response) { 
      if (err) { 
       reject(err); 
       return; 
      } 
      var f = response.files; 
      if (f.length == 0) { 
       console.log('No files found.'); 
      } 
      else { 
       var key = 'files'; // Why this indirection?? 
       resolve({[key]: f.map(file => file.name + ' ' + file.id)}); 
       // Without the indirection it would be: 
       // resolve({files: f.map(file => file.name + ' ' + file.id)}); 
      } 
     }); 
    }); 
} 

을, 우리는 관계인 것 같습니다 key 간접으로 한, 그것은 간단하게 될 것입니다 :

function findFiles(auth) { 
    return drivePromisified.files.list({ 
     auth: auth, 
     folderId: '****************', 
     q: "mimeType contains 'application/pdf' and trashed = false" 
    }).then(files => ({files: files.map(file => file.name + ' ' + file.id)})); 
} 

또는 async 함수로 await 사용 :

async function findFiles(auth) { 
    const files = await drivePromisified.files.list({ 
     auth: auth, 
     folderId: '****************', 
     q: "mimeType contains 'application/pdf' and trashed = false" 
    }); 
    return {files: files.map(file => file.name + ' ' + file.id)}; 
} 
+0

답장을 보내 주셔서 감사합니다. 실제로'findFile' 함수도 비동기 적이기 때문에 약속을 지킬 수있을만큼 친절하십니까 – AlwaysHungrie

+0

@AlwaysHungrie : 내용을 표시하지 않았으므로 까다 롭습니다. :-)하지만 그것은 어쨌든 독자를위한 운동으로 가장 좋습니다 : 그냥 약속을 되풀이하게하십시오. 예를 들어, [readdir'] (https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback)을 사용한다면, 위의'readFile'처럼 우리는 약속을하고, 아마도 결과를 변환해야하는 경우 '다음'이 연결됩니다.) –

+0

죄송합니다.'findFile'을 포함하도록 질문을 편집했습니다. drive.files를 반환하려고했습니다.그러나 코드는 catch (e) 블록으로 이동합니다. – AlwaysHungrie

관련 문제