Javascript 正确使用带有wait/Async的承诺

Javascript 正确使用带有wait/Async的承诺,javascript,node.js,promise,ecmascript-2017,Javascript,Node.js,Promise,Ecmascript 2017,我在理解Promise功能如何工作时遇到了一些问题,我以前使用过Bluebird,但我想尝试学习新的await/async标准,以便作为一名程序员改进。我使用了async/await,并在我认为合适的地方创建了承诺,但是函数仍然在无序执行 我在最新版本的Node with Webpack上运行此操作,没有收到任何有意义的错误。它运行得很好,只是不像预期的那样。运行时的输出是: Searching the Web for: Test String Web search Completed! Pro

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

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

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.');
    }
  },
};
consthttps=require('https');
//用有效的订阅密钥替换subscriptionKey字符串值。
const subscriptionKey='';
const host='api.cognitive.microsoft.com';
常量路径='/bing/v7.0/search';
常量响应\u处理程序=异步(响应)=>{
返回新承诺((解决、拒绝)=>{
让body='';
响应.on('数据',(d)=>{
body+=d;
决议(机构);
});
响应。在('end',()=>{
console.log('\n相关头:\n');
for(响应中的常量标头。标头)
//标题键由Node.js小写
{
if(header.startsWith('bingapi-')| | header.startsWith('x-msedge-')){console.log(`${header}:${response.headers[header]}})}
}
body=JSON.stringify(JSON.parse(body),null“”);
//console.log('\nJSON测试响应:\n');
//控制台日志(主体);
});
响应时间('error',(e)=>{
log(`Error:${e.message}`);
});
log('Response Handler Completed!');
});
};
const bing\u web\u search=async(search)=>{
返回新承诺((解决、拒绝)=>{
log(`在Web上搜索:${search}`);
常量请求参数={
方法:“GET”,
主机名:主机,
路径:`${path}?q=${encodeURIComponent(search)}&$responseFilter=${encodeURIComponent('Webpages')}&count=${50}`,
标题:{
“Ocp Apim订阅密钥”:subscriptionKey,
},
};
const req=https.request(请求参数、响应处理程序);
log('Web搜索已完成!');
控制台日志(请求主体);
请求结束();
});
};
module.exports={
搜索:异步(搜索)=>{
if(subscriptionKey.length==32){
const result=等待bing\u web\u搜索(搜索);
console.log('Search Completed');
}否则{
log('无效的Bing搜索API订阅密钥!');
log('请将您的粘贴到源代码中');
}
},
};

有点晚了,但下面的内容应该会让您有所收获,我对代码做了更改。如果你有任何问题,请告诉我

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

如果你有很多搜索,那么也许你想用某种或某种方式来限制回复的数量。如果需要帮助,请告诉我。

从异步函数返回承诺没有任何意义。那么它根本不需要是异步的。而且您永远不会调用
resolve
而且,如果出现错误,您应该拒绝()!也许使用fetch api会更简单,它返回一个承诺,工作起来有点像
$。ajax
:我将尝试使用fetch而不是https,关于该模块的文档似乎不多。谢谢大家!承诺是ES2015(ES6)的一部分,
async/await
是ES2017的一部分。您好,HMR,这并没有解决回复的顺序问题,但这些评论确实有助于我自己的理解,因此我对此表示感谢!我将尝试从https迁移到fetch,看看这是否简化了操作。如果多个请求的顺序很重要,您可以使用search和use
Promise将一系列搜索对象映射到promises。all
(更新了答案并提供了示例)
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!');
    }
  },
};
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)
    );
  }
)