首页 文章

正确使用Aise / Async的Promise

提问于
浏览
4

我在理解Promise功能如何工作方面遇到了一些问题,我之前使用过Bluebird,但我想尝试学习新的await / async标准,以便作为程序员进行改进 . 我已经使用了async / await并在我认为合适的情况下创建了promises但是函数仍然无序执行 .

我在最新版本的Node with Webpack上运行它,我没有收到任何有意义的错误 . 它运行良好,不像预期的那样 . 运行时我的输出是:

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

理想情况下,我希望它回应:

Searching the Web for: Test String
Response Handler Completed
Web search 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.');
    }
  },
};

1 回答

  • 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!');
        }
      },
    };
    

    [update]

    您的评论建议您不要正确调用搜索或处理它正确返回的承诺 . 您无法控制响应在第一个请求最后返回的一组响应中所花费的时间 . 这就是你有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 periodactive connections来限制响应的数量 . 如果您需要帮助,请告诉我 .

相关问题