关于async模块,eachOf的callback问题
发布于 6 年前 作者 zhongshiji 3356 次浏览 来自 问答

7.png R481YKCD%O54.png 如图这是async的eachOf方法官方文档以及demo,我是个小白,研究了挺久没看懂,我的问题是: 这里iteratee异步函数的三个参数里,最后的callback(如图所示)是什么时候被调用? 照我的理解是循环一次调用一次,但显然不是这样。 PS:demo的运行结果是输出三个文件的所有内容的一个{}。

26 回复

求大神指点

循环一次调用一次,正常情况下调用的次数等于obj键的个数。

@zhongshiji 另外你用错了,应该是async.eachOf

@lovegnep 这个是别名,两个名字都可以用,是官网demo

@lovegnep 请帮我看下这个 image.png 为了测试一下这个callback,运行结果没有按理想的输出一个数组,这是为什么呢?

@zhongshiji 输出结果是啥呢?报错了?

来自酷炫的 CNodeMD

@lovegnep 没有报错,输出了20项“写入成功",但是字符1跟arr没有输出。(有两项没爬取到请忽略) image.png

@lovegnep 如果将arr.push(key)与callback()两句往下放在下面err = > {}的正上面(如下图),倒是能正常输出arr数组与“写入成功”,但是为何不能像截图一样放在fs.writeFile()里面,这是我不能理解的。(官网demo中callback()也是放在fs.readFile()里面)

@zhongshiji articleurl的长度是多少呢,如果callback的调用次数不等于长度,那么是不会走到最后的打印1和数组的。writefile发生错误不要返回,把return去掉

来自酷炫的 CNodeMD

eachOf(coll, iteratee, callbackopt) iteratee的第三个参数callback在每次执行iteratee中一定要运行到,即如果iteratee中发生错误则调用callback(err),否则callback(null)

另外建议你不要贴图片,想改下你的代码没法复制呀

@lovegnep

async.eachOf(articleUrls,function (value, key, callback) {
			request(value, function (error, response, body) {
				if (!error && response.statusCode === 200) {
					const $ = cheerio.load(body)
					fs.writeFile(path.join(__dirname, `./教务处公告/${key}` + '.txt'), $('h1').text() + $('#content p').text(), function(err) {
						if (err) {
							return callback(err)
						}
						try {
							arr.push(key)
							console.log(`第${ key + 1 }项`, '写入成功')
						} catch (e) {
							return callback(e)
						}
						callback()
					})
				}
			})
		}, err => {
			if (err) {
				console.error(err.message)
			}
			console.log('1', arr)
		})

@lovegnep 改成了这样,也是不行。没输出数组,去掉return也是一样。

@lovegnep articleUrls的长度为20,因为有两条我的规则没涵盖到,只抓取到18条。

@lovegnep 我大概抓住了一点重点,通过fs.writeFile本地只生成了18个txt文件,但应该是生成20个,问题出在哪儿了?,而且少掉的两个刚好是因为

fs.writeFile(file, data[, options], callback)

中data为空的那两个。

如果下面这样还不行的话我也不知道为啥了

async.eachOf(articleUrls,function (value, key, callback) {
	request(value, function (error, response, body) {
		if (!error && response.statusCode === 200) {
			const $ = cheerio.load(body)
			fs.writeFile(path.join(__dirname, `./教务处公告/${key}` + '.txt'), $('h1').text() + $('#content p').text(), function(err) {
				if (err) {
					return callback(err)
				}
				try {
					arr.push(key)
					console.log(`第${ key + 1 }项`, '写入成功')
				} catch (e) {
					return callback(e)
				}
				callback()
			})
		}else{
			callback(err)
		}
	})
}, err => {
	if (err) {
		console.error(err.message)
	}
	console.log('1', arr)
})

@zhongshiji l加个else判断下

	if (!error && response.statusCode === 200)esle{....}

@lovegnep 你这样我运行了下,在else{}中callback(err)报错: err is not defined.

@lovegnep 您之前说“iteratee的第三个参数callback在每次执行iteratee中一定要运行到”,但是我iteratee中

fs.writeFile(file, data[, options], callback)

有两个data为空,由key并未生成那两个.txt文件,是不是因为这个,callback有两次没有运行到呢?

@zhongshiji 是的,用下面这样就行了

async.eachOf(articleUrls,function (value, key, callback) {
	request(value, function (error, response, body) {
		if (!error && response.statusCode === 200) {
			const $ = cheerio.load(body)
			fs.writeFile(path.join(__dirname, `./教务处公告/${key}` + '.txt'), $('h1').text() + $('#content p').text(), function(err) {
				if (err) {
					return callback(err)
				}
				try {
					arr.push(key)
					console.log(`第${ key + 1 }项`, '写入成功')
				} catch (e) {
					return callback(e)
				}
				callback()
			})
		}else{
			callback('请求出错')
		}
	})
}, err => {
	if (err) {
		console.error(err.message)
	}
	console.log('1', arr)
})

@lovegnep 问题解决,最后是这样:

async.eachOf(articleUrls, function(value, key, callback) {
			request(value, function(error, response, body) {
				if (!error && response.statusCode === 200) {
					const $ = cheerio.load(body)
					fs.writeFile(path.join(__dirname, `./教务处公告/${key}` + '.txt'), $('h1').text() + $('#content p').text(), function(err) {
						if (err) {
							return callback(err)
						}
						try {
							arr.push(key)
							console.log(`第${ key + 1 }项`, '写入成功')
						} catch (e) {
							return callback(e)
						}
						callback()
					})
				} else {
					callback(error)
				}
			})
		}, err => {
			if (err) {
				console.error(err.message)
			}
			console.log('1', arr)
		})

else中callback参数是error,不是err,也正如您所说。结果是这样: image.png

@lovegnep 非常感谢!我对callback()的理解又深了一点,最后再请问一下,async.eachOf()的iteratee第三个参数callback是不是循环一次调用一次,在callback的次数==articleUrls.length的时候,async.eachOf()的第三个参数callback才被触发?

是的,请看官方文档:

A callback which is called when all iteratee functions have finished, or an error occurs. Invoked with (err).

回到顶部