You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用request模块时Generator函数的yield为何不生效?

问题出在哪?

你这段代码的核心问题有两个:

  1. Generator函数不会自己跑起来:调用fetch(obj)只是得到了一个迭代器对象,函数体里的代码(打印2、请求数据这些)根本没执行——必须手动调用迭代器的next()方法,才能推进Generator的执行流程。
  2. forEach做不到串行异步处理:forEach是同步遍历,它会瞬间创建所有Generator对象,但不会等待每个请求完成,完全不符合你“处理完当前URL再拿下一个”的需求。
怎么解决?

Bluebird本身就有工具帮你搞定Generator的自动执行,再配合它的串行遍历方法,就能完美实现你的需求。看重构后的代码:

var Promise = require("bluebird");
var request = Promise.promisify(require("request"), { multiArgs: true });
Promise.promisifyAll(request, { multiArgs: true });

var url_arr = [
  "https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=AIzaSyDe3MyoHI6aSbYKdHOXloz9QepAMfes9XE",
  "https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=AIzaSyDe3MyoHI6aSbYKdHOXloz9QepAMfes9XE"
];

// 用Promise.coroutine包装Generator,让它自动执行
const fetchUrl = Promise.coroutine(function* (obj) {
  console.log("2");
  // yield会自动等待请求完成,直接拿到结果
  const myobj = yield request.getAsync(obj);
  console.log("3", myobj);
  return myobj;
});

// 用Promise.each串行处理数组,前一个请求完再处理下一个
Promise.each(url_arr, (obj) => {
  console.log("1", obj);
  return fetchUrl(obj);
})
.then((allResults) => {
  console.log("所有请求都完成啦", allResults);
})
.catch((err) => {
  console.error("某个请求出错了", err);
});
为什么这么改?
  • Promise.coroutine:这个工具会把你的Generator函数转换成一个返回Promise的函数,内部自动帮你调用迭代器的next(),直到Generator执行完毕。而且yield后面的Promise完成后,会自动把结果赋值给前面的变量,不用手动处理promise的then。
  • Promise.each:Bluebird的这个方法专门用来做串行异步遍历——它会等当前元素的处理函数(这里是fetchUrl(obj))完成后,再处理下一个元素,完全满足你“先获取当前URL数据,再处理下一个”的要求。
  • 另外,你原来写的request.getAsync(obj).promise()可以简化成request.getAsync(obj),因为promisifyAll已经给request添加了带Async后缀的异步方法,这些方法直接返回Promise。

现在运行这段代码,控制台会按1 -> 2 -> 3 -> 1 -> 2 -> 3的顺序打印,完全符合你的预期。

内容的提问来源于stack exchange,提问作者Amulya Kashyap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:49:21