【发布时间】:2022-01-29 07:05:07
【问题描述】:
对使用异步函数进行编程完全陌生。 node.js 也是新的,这可能会增加我的问题。我读了很多书并不断遇到类似的问题,似乎我一直在随机让异步代码的某些部分工作,而其他部分则没有。这是我所拥有的简化版本:
基本上我是在搜索音乐网站,抓取所有结果 (scraper_start.js),然后将其发送到 scrape_individual.js 以收集数据。它目前能够获取所有数据,但是当它下载专辑封面时“为时已晚”。
图像确实会记录到控制台,但只有在返回信息之后。另外,如果您有任何好的资源来学习异步编程,请分享它们——我一直无法找到一个既漂亮又干净的网站,并且提供了足够大的示例以使它们变得现实(例如同时工作的多个异步函数和有时相互依赖)。请也批评我的代码 - 我正在努力学习!
文件 scraper_start.js:
const rp = require('request-promise');
const cheerio = require('cheerio');
const scrape = require('./scrape_individual.js');
const base_url = 'https://www.test.ca';
const url = 'https://www.test.ca/search?mysearchstring';
rp(url)
.then(function(html)
{
const $ = cheerio.load(html);
var results = []
var hits = $('h3 > a').length;
console.log("TOTAL HITS: " + hits);
results = $('h3 > a').map(function(i,v){ return $(v).attr('href'); }).get()
return Promise.all(
results.map(function(url)
{
return scrape(base_url + url);
})
);
})
.then(function(my_data)
{
console.log(my_data);
});
文件 scrape_individual.js:
const rp = require('request-promise');
const cheerio = require('cheerio');
var info = {}
const scrape = function(url)
{
return rp(url)
.then(function(html)
{
const $ = cheerio.load(html);
if (!html.includes('contentType = "Podcast"'))
{
info = {
title: $('h2.bc-heading:first').text(),
img3: null};
img_data($('.bc-image-inset-border').attr('src'))
.then(function(v)
{
console.log(v);
info.img3 = v; // Log the value once it is resolved
})
.catch(function(v) {
});
return info;
}
})
};
function img_data(src)
{
return new Promise(function(resolve, reject)
{
const { createCanvas, loadImage } = require('canvas');
loadImage(src).then((image) =>
{
const canvas = createCanvas(image.width, image.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
resolve(canvas.toDataURL());
});
});
}
module.exports = scrape;
更新:带有 ASYNC / AWAIT 的新代码
scraper_start.js:
const rp = require('request-promise');
const cheerio = require('cheerio');
const scrape = require('./scrape_individual.js');
const base_url = 'https://www.test.ca';
const url = 'https://www.test.ca/search?mysearchstring';
var data = [];
async function get_links(url)
{
let html = await rp(url);
const $ = cheerio.load(html);
var results = [];
var hits = $('h3 > a').length;
console.log("TOTAL HITS: " + hits);
hrefs = $('h3 > a').map(function(i,v){ return $(v).attr('href'); }).get()
await Promise.all(hrefs.map(async (href) =>
{
let data_single = await scrape.scrape_book3(base_url + href);
data.push(data_single);
}));
//QUESTION AREA 1: This data works great with all info.
console.log(data);
return data
}
get_links(url);
//QUESTION AREA 2: This data gets printed before getting the actual data returned.
console.log(data);
scrape_individual.js:
const rp = require('request-promise');
const cheerio = require('cheerio');
var info = {}
//scrape2(url)
module.exports.scrape_individual = scrape2;
async function scrape2(url)
{
let html = await rp(url);
const $ = cheerio.load(html);
if (!html.includes('contentType = "Podcast"'))
{
let my_image = await img_data($('.bc-image-inset-border').attr('src'));
info = {title: $('h2.bc-heading:first').text(),
img3: my_image};
//console.log(info);
return info;
}
}
async function img_data(src)
{
const { createCanvas, loadImage } = require('canvas');
let image = await loadImage(src);
const canvas = createCanvas(image.width, image.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
//console.log(canvas.toDataURL());
return canvas.toDataURL();
}
这段代码现在很好用。也更容易理解。当我试图掌握这一点时,请随时批评。我现在的问题更像是一个一般性的编码问题。
在最终结果(数据)结束的 scraper_start.js 中,我用“QUESTION AREA 1”和“QUESTION AREA 2”标记了两个 cmets
问题区域 1:工作得很好,我认为这是因为它在 async 函数中 问题区域 2:在 async 函数之外,还没有返回对象,因为没有什么可说的 await。有没有办法让它等待?
我的问题很重要。我不能使用等待,因为据我了解它不在异步函数中。这是否意味着如果我想维护重要的订单,我的所有代码都需要在函数中?什么是最佳实践?为什么不将每个函数都称为异步函数?
编辑:修正错别字 edit2:添加了 ASYNC / AWAIT 修改
【问题讨论】:
-
img_data(...).then->return img_data(...).then(() => {...., return info}如果你不返回一个 Promise,它就会从你的 Promise 链中分离出来。 IOW:你不能这样做 ->somePromise(); return somePromiseResult,,应该是return somePromise().then(() => { return somPromiseResult }公平地说,如果你使用async / await,promise 更容易推理 -
谢谢基思。老实说,目前这有点超出我的想象。我确实读过 async / await 但所有这些不同的方式都让我头疼。你认为我应该那样学习并改用那样吗?
-
使用
async / await,对 Promises 有很好的理解当然是个好主意,因为它们之间不是相互独立的。但是,如果您开始大量使用async编程,我当然会建议您研究一下。还要尽量避免使用catch,就像大多数语言的异常大部分应该在顶层处理一样。此外,不是顶级的 catch 应该很少不重新加注,否则程序流程可能会不同步。 -
谢谢基思!我花了一些时间完全专注于异步/等待。清理了我的代码。在以另一种方式挣扎之后更容易理解!如果你有时间帮忙,我添加了一些问题!再次感谢您引导我朝这个方向前进!
标签: javascript node.js asynchronous async-await