Nodejs中关于async的使用求解

Nodejs中关于async的使用求解

//二.采集目标内容的地址
$.each(one_url,function(i,v){
var temp = v.split(’-’)
temp[1] = 2
console.log(‘a’)
async.series([
function(){
n.get(temp.join(’-’),{decode_response:false,encoding:‘binary’,follow:1},list_url)
}
])
console.log(‘ccccc’)
})
//二。采集分类列表的链接地址
var list_url = function(error,response,body){
var content = new iconv(‘gbk’,‘UTF-8//TRANSLIT//IGNORE’).convert(new Buffer(body,‘binary’)).toString()
console.log($(content).find(’.last’).attr(‘href’))
}

日志中输出

C:\nodejs\node.exe cj39.js
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
a
ccccc
undefined
/browse/313-2-2188.html
/browse/23-2-893.html
/browse/14440-2-2188.html
/browse/320-2-2188.html
/browse/322-2-2188.html
undefined
/browse/19018333-2-2188.html
/browse/3157-2-2188.html
/browse/3162-2-2188.html
/browse/323-2-2188.html
/browse/309-2-2188.html
/browse/3166-2-2188.html
/browse/311-2-2188.html
/browse/3163-2-2188.html
/browse/27-2-2188.html
/browse/271-2-2188.html

可以看到async里面没有等待函数执行完成就执行了日志console.log(‘ccc’)的输出。求怎么按顺序执行?


7 回复

在Node.js中使用async库来管理异步操作是一个常见的需求,特别是当你需要确保一系列异步任务按顺序执行时。你遇到的问题是因为async.series中的函数是立即执行的,而你希望它们按照序列的方式执行。

解决方案

为了确保异步操作按顺序执行,你可以使用async.series的正确方式。此外,你需要确保在所有异步操作完成后才执行后续的日志输出。

示例代码

const async = require('async');
const axios = require('axios');
const iconv = require('iconv-lite');

// 模拟n.get方法
const n = {
    get: (url, options, callback) => {
        axios.get(url, { responseType: 'arraybuffer' })
            .then(response => {
                const body = iconv.decode(Buffer.from(response.data), 'gbk');
                callback(null, body);
            })
            .catch(error => {
                callback(error);
            });
    }
};

// 分类列表链接地址处理函数
const list_url = (error, response, body) => {
    if (error) {
        console.error("Error:", error);
        return;
    }
    const content = iconv.decode(Buffer.from(body), 'gbk');
    const href = $(content).find('.last').attr('href');
    if (href) {
        console.log(href);
    } else {
        console.log('undefined');
    }
};

// 主逻辑
const one_url = [
    "browse/313-1-2188.html",
    "browse/23-1-893.html",
    "browse/14440-1-2188.html",
    // 更多URL...
];

async.series(
    one_url.map(url => {
        return (callback) => {
            let temp = url.split('-');
            temp[1] = 2;
            const modifiedUrl = temp.join('-');
            n.get(modifiedUrl, { decode_response: false, encoding: 'binary', follow: 1 }, list_url);
            callback(); // 确保回调被调用
        };
    }),
    (err) => {
        if (err) {
            console.error("Async series error:", err);
            return;
        }
        console.log('All tasks completed.');
    }
);

解释

  1. 模拟n.get方法:这里我们使用axios来模拟n.get方法,它会发送HTTP请求并返回响应体。
  2. list_url函数:处理HTTP响应,并提取所需的链接。
  3. async.series:使用async.series来确保每个URL对应的异步任务按顺序执行。每个任务都包含一个回调函数,该函数在任务完成后调用,以确保async.series可以继续执行下一个任务。
  4. callback():在每个任务的最后调用callback()来通知async.series当前任务已完成。

通过这种方式,你可以确保所有异步任务按顺序执行,并且在所有任务完成后打印“All tasks completed.”。


async根本就不是这么用的吧,那个地方用series有什么意义。。

这个each怎么使用?第2个参数我不太理解。。可否给个例子说明?

这是 async.map 的正确用法:

var array = [0, 1, 2, 3];

async.map(array, function (item, callback) { console.log("Transforming item: " + item); var transformed = item + 1; callback(null, transformed); }, function (error, results) { console.log(results); // => [1, 2, 3, 4] });

楼主可能对非阻塞模型和 callback 的语法地位都不理解,建议先学点入门的东西再写代码……

你遇到的问题是因为 async.series 中的任务需要一个回调函数来通知它任务已经完成。你当前的代码中没有提供这个回调函数,因此 async.series 认为任务已经立即完成,所以导致后续的 console.log('ccccc') 会立即执行。

为了确保任务按顺序执行,你需要在任务函数中调用传入的回调函数来表示任务已完成。以下是修改后的代码示例:

const async = require('async');

$.each(one_url, function(i, v) {
    var temp = v.split('-');
    temp[1] = 2;
    
    console.log('a');
    
    async.series([
        function(callback) {
            n.get(temp.join('-'), { decode_response: false, encoding: 'binary', follow: 1 }, function(error, response, body) {
                list_url(error, response, body);
                callback(); // 调用回调函数表示任务完成
            });
        }
    ]);
    
    console.log('ccccc');
});

// 分类列表链接地址采集
var list_url = function(error, response, body) {
    if (error) {
        console.error("Error:", error);
        return;
    }

    var content = new iconv('gbk', 'UTF-8//TRANSLIT//IGNORE').convert(new Buffer(body, 'binary')).toString();
    console.log($(content).find('.last').attr('href'));
};

在这个修改后的版本中,我添加了一个回调函数 callback 来通知 async.series 任务已经完成。这样可以确保在所有任务完成后才会继续执行后续的代码。

回到顶部