2017-12-04 13 views
3

약속 기능이 어떻게 작동하는지 이해하는 데 몇 가지 문제가 있습니다. 이전에 Bluebird를 사용했지만 프로그래머로 개선하기 위해 새로운 await/async 표준을 배우려고했습니다. 나는 async/await를 사용하여 적절한 기능을하지만 적절하게 작동하지 않는 약속을 만들었습니다.Await/Async와의 약속 사용 올바르게 함

Webpack을 사용하는 노드의 최신 버전에서 실행 중이므로 의미있는 오류가 발생하지 않습니다. 정상적으로 잘 돌아 가지 않습니다. 그것을 실행 내 출력은 다음과 같습니다

Searching the Web for: Test String 
Response Handler Completed 
Web search Completed 

을 그리고 내 대답 처리기의 출력을 반환 :

Searching the Web for: Test String 
Web search Completed! 
Promise { <pending> } 
Response Handler Completed! 

은 이상적으로는 응답 싶습니다.

누구든지 내 실수를 감지 할 수 있습니까?

const https = require('https'); 

// Replace the subscriptionKey string value with your valid subscription key. 
const subscriptionKey = '<samplekey>'; 

const host = 'api.cognitive.microsoft.com'; 
const path = '/bing/v7.0/search'; 

const response_handler = async (response) => { 
    return new Promise((resolve, reject) => { 
     let body = ''; 
     response.on('data', (d) => { 
     body += d; 
     resolve(body); 
     }); 
     response.on('end',() => { 
     console.log('\nRelevant Headers:\n'); 
     for (const header in response.headers) 
       // header keys are lower-cased by Node.js 
      { 
      if (header.startsWith('bingapis-') || header.startsWith('x-msedge-')) { console.log(`${header}: ${response.headers[header]}`); } 
     } 
     body = JSON.stringify(JSON.parse(body), null, ' '); 
     //console.log('\nJSON Test Response:\n'); 
     //console.log(body); 
     }); 
     response.on('error', (e) => { 
     console.log(`Error: ${e.message}`); 
     }); 
     console.log('Response Handler Completed!'); 

    }); 
}; 

const bing_web_search = async (search) => { 
    return new Promise((resolve, reject) => { 
    console.log(`Searching the Web for: ${search}`); 
    const request_params = { 
    method: 'GET', 
    hostname: host, 
    path: `${path}?q=${encodeURIComponent(search)}&$responseFilter=${encodeURIComponent('Webpages')}&count=${50}`, 
    headers: { 
     'Ocp-Apim-Subscription-Key': subscriptionKey, 
    }, 
    }; 

    const req = https.request(request_params, response_handler); 

    console.log('Web search Completed!'); 
    console.log(req.body); 
    req.end(); 
    }); 
}; 

module.exports = { 
    search: async (search) => { 
    if (subscriptionKey.length === 32) { 
     const result = await bing_web_search(search); 
     console.log('Search Completed'); 
    } else { 
     console.log('Invalid Bing Search API subscription key!'); 
     console.log('Please paste yours into the source code.'); 
    } 
    }, 
}; 
+3

비동기 함수에서 약속을 반환하는 것은 의미가 없습니다. 그렇다면 비동기 일 필요는 없습니다. 그리고 절대로'resolve'라고 부르지 마십시오 –

+0

또한 오류 발생시 거부()해야합니다! – falsarella

+0

아마도 fetch api를 사용하면 더 간단해질 것이고, 약속을 되 돌리며'$ .ajax'와 같이 작동합니다 : https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API – HMR

답변

0

조금 늦었지만 다음과 같이 설정해야합니다. 코드를 변경했습니다. 궁금한 점이 있으면 알려주세요.

const https = require('https'); 

// Replace the subscriptionKey string value with your valid subscription key. 
const subscriptionKey = '<samplekey>'; 

const host = 'api.cognitive.microsoft.com'; 
const path = '/bing/v7.0/search'; 

const response_handler = (resolve,reject) => (response) => { // no need for async, you return a promise 
    //this one does not return anything, it's the handler for the response and will resolve 
    // or reject accordingly 
    let body = ''; 
    response.on('data', (d) => { 
    body += d; 
    //cannot resolve yet, we're not done 
    // you can resolve on end maybe? I don't know nodejs http 
    // if end event is called when request fails then end would not 
    // be the correct way either, better use fetch api 
    //resolve(body); 
    }); 
    response.on('end',() => { 
    console.log('\nRelevant Headers:\n'); 
    for (const header in response.headers) 
    // header keys are lower-cased by Node.js 
    { 
     if (header.startsWith('bingapis-') || header.startsWith('x-msedge-')) { console.log(`${header}: ${response.headers[header]}`); } 
    } 
    body = JSON.stringify(JSON.parse(body), null, ' '); 
    resolve(body);//resolving the promise returned by bing_web_search 
    //console.log('\nJSON Test Response:\n'); 
    //console.log(body); 
    }); 
    response.on('error', (e) => { 
    console.log(`Error: ${e.message}`); 
    //need to reject with the error 
    reject(e); 
    }); 
    console.log('Response Handler Completed!'); 

}; 
//no need to specify async, you are not awaiting anything 
// you are creating a promise, when using non promise asynchronous 
// functions that work with callbacks or event emitting objects 
// you need resolve and reject functions so you have to return 
// new Promise(
// (resolve,reject)=>somecallbackNeedingFunction((err,result)=> 
//  err ? reject(err) : resolve(result) 
// ) 
// ) 
const bing_web_search = (search) => { 
    return new Promise((resolve, reject) => { 
    console.log(`Searching the Web for: ${search}`); 
    const request_params = { 
     method: 'GET', 
     hostname: host, 
     path: `${path}?q=${encodeURIComponent(search)}&$responseFilter=${encodeURIComponent('Webpages')}&count=${50}`, 
     headers: { 
     'Ocp-Apim-Subscription-Key': subscriptionKey, 
     }, 
    }; 

    const req = https.request(
     request_params, 
     response_handler(resolve,reject)//passing this resolve and reject 
    ); 
    //no, request not completed, we just started 
    console.log('Web search Completed!'); 
    // console.log(req.body); // nothing to log here 
    req.end(); 
    }); 
}; 

module.exports = { 
    search: async (search) => { 
    if (subscriptionKey.length === 32) { 
     //did not change anything bing_web_search returns a promise 
     // so you can just await it 
     const result = await bing_web_search(search); 
     console.log('Search Completed'); 
     //this will resolve with the results 
     return result 
    } else { 
     console.log('Invalid Bing Search API subscription key!'); 
     console.log('Please paste yours into the source code.'); 
     //the caller of this function can handle the rejection 
     return Promise.reject('Invalid Bing Search API subscription key!'); 
    } 
    }, 
}; 

[업데이트]

귀하의 의견은 제대로 검색 전화를 걸거나 제대로 반환 약속을 처리하지 않는 것이 좋습니다. 첫 번째 요청이 마지막으로 반환 할 수있는 응답 집합에서 응답이 소요되는 시간을 제어 할 수 없습니다. 당신이 검색을 많이 가지고있는 경우가 Promise.all

const searchObjects = [s1,s2]; 
const Fail = function(reason){this.reason=reason;}; 
Promise.all(
    searchObjects.map(
    searchObject => obj.search(searchObject) 
    .then(
     x=>[x,searchObject]//if resolve just pass result 
     ,err =>new Fail([err,searchObject])//if reject add a Fail object with some detail 
    ) 
) 
) 
.then(
    results => { 
    console.log(
     "resolved results:", 
     results.filter(([r,_])=>(r&&r.constructor)!==Fail) 
    ); 
    console.log(
     "failed results:", 
     results.filter(([r,_])=>(r&&r.constructor)===Fail) 
    ); 
    } 
) 

이 어쩌면 당신이 특정 time period 또는 active connections withing에 응답의 양을 스로틀 할 이유입니다. 도움이 필요하면 알려주세요.

+0

안녕하세요, HMR, 응답의 순서가 해결되지 않았지만 의견이 내 자신의 이해에 도움이되었습니다. 감사합니다. https에서 마이 그 레이션하여 페치를 단순화하는지 확인합니다. – Crafty

+0

여러 요청의 순서가 중요한 경우 검색을 사용하여 검색 개체의 배열을 약속에 매핑하고 'Promise.all'을 사용합니다 (예를 들어 업데이트 된 답변) – HMR