首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NodeJS异步编程

NodeJS异步编程
EN

Stack Overflow用户
提问于 2022-01-28 19:05:06
回答 1查看 68关注 0票数 0

对使用异步函数编程完全陌生。node.js也是新的,这可能会增加我的问题。我读了很多书,并不断地遇到类似的问题,似乎我正在随机地让异步代码的某些部分工作,而其他部分则不起作用。

本质上,我正在搜索一个音乐站点,删除所有的结果(scraper_start.js),然后将其发送到scrape_individual.js收集数据。它目前能够获得所有的数据,但当它下载专辑艺术,它进入“太晚”。

图像确实被记录到控制台,但只有在信息被返回之后。此外,如果你有任何好的资源来学习异步编程,请分享它们-我还没有找到一个好的,干净的网站,并进入足够大的例子,他们变得现实(例如多个异步函数一次工作,有时相互依赖)。请批评我的代码以及-我正在努力学习!

文件scraper_start.js:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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 /等待的新代码

scraper_start.js:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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中,我用“问题区域1”和“问题区域2”标记了两个注释

问题区域1:工作完全正常,因为它位于异步函数的第2区:异步函数之外,还没有返回对象,因为没有什么可说的等待。有什么办法让它等待吗?

我的问题很有说服力。据我所知,由于它不在异步函数中,所以我不能使用它。这是否意味着,如果我想维护一个重要的顺序,我的所有代码都需要处于函数中吗?什么是最佳实践?为什么不将每个函数调用为异步呢?

编辑:修复排版edit2:添加ASYNC /等待修改

EN

回答 1

Stack Overflow用户

发布于 2022-01-28 23:05:07

问题区域2在捕获数据之前返回,因为您告诉JS最后一个函数没有等待任何人,所以它是同步运行的。但事实是,它实际上是在等待某个人,它在等待get_links()

因此,打印数据的一种方法是:

代码语言:javascript
复制
    async printer(){
    const returnedData = await get_links(URL);
    console.log(returnedData)
    }
    printer();

如果您想使用从异步函数返回的数据,您需要使用wait调用它,这样JS就知道在继续之前它需要等待已解决的或拒绝的承诺,否则它将返回一个Promise<pending>。所有的人都在等待需要在异步中。一开始,听起来像是一个无穷无尽的循环,但实际上并非如此。

例如,在我们的示例中,您不需要任何其他异步来调用打印机()(因为没有其他函数依赖于这个函数),我希望它是有意义的,但在开始时承诺需要一些时间才能理解它们。在我看来,异步/等待是理解承诺的一种祝福,一旦你意识到它以及它们是如何运作的,你就能更好地理解决心/拒绝的方式。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70898982

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档