gpt4 book ai didi

javascript - 了解Node.JS使用async.waterfall如何执行外部功能

转载 作者:数据小太阳 更新时间:2023-10-29 05:32:29 26 4
gpt4 key购买 nike

我需要使用async.js模块执行异步功能。
但是当我执行外部功能时,我遇到了一些问题。

该代码通过得很好。

但是当我将全局变量更改为局部变量时,无法使用参数进行设置。

var async = require('async');
var ogs = require('open-graph-scraper');

// global variables
var param1 = {url: 'http://www.google.com/'};
var param2 = {url: 'https://www.yahoo.com/'};

function function1(callback){
ogs(param1, function(error, data1) {
callback(null, data1);
});
}
function function2(data1, callback){
ogs(param2, function(error, data2) {
callback(null, data1, data2);
});
}
function function3(data1, data2, callback){
console.log(data1);
console.log("---------------");
console.log(data2);
}

(function temp() {
async.waterfall([function1, function2, function3],
function(err, result){
console.log(result);
console.log(err);
if(err) console.log(err);
}
);
})();

如果param1和param2更改为局部变量,就像这样。
(function temp() {
var param1 = {url: 'http://www.google.com/'};
var param2 = {url: 'https://www.yahoo.com/'};
async.waterfall([function1, function2, function3],
function(err, result){
console.log(result);
console.log(err);
if(err) console.log(err);
}
);
})();

如何在function1()或function2()中使用“param”

我无法更改本地的功能类型
async.waterfall([
function(callback){
},
function(data,callback){
}],
function(err){
if(err) console.log(err);
}
);

最佳答案

psst!我正在使用某些ES6语法,请至少在 Node 6上运行代码段,好吗?

异步任务可以建模为带有回调的函数:

function task(arg1, arg2, callback) {
// ...
callback(null, result);
}
task(arg1, arg2, (err, result) => {
handle(result);
});

但是有另一种约定通常可以简化事情:
function task(arg1, arg2) {
// ...
return Promise.resolve(result);
}
task(arg1, arg2).then(handle(result));

尽管两种约定都有意义,但我已经看到第二种方法在实践中更有用,可以编写具有良好错误处理能力的简单异步代码。

要把握的最重要的点是:
  • 函数返回一个值;异步任务返回对 future 值(value)的 promise 。
  • 当异步任务完成时,它将promise标记为“resolved”。
  • 如果异步任务失败,则不会引发异常,而是将 promise 与错误一起标记为“已拒绝”。
  • 返回的promise也是一个对象。您甚至可以在完成之前使用它来做有用的事情。运行异步任务的代码不必与对任务结果感兴趣的代码放在同一位置。

  • 关于promise的重要一点是,保证它们是异步的,与回调不同:
    // callbacks
    myTask(1, 2, (err, result) => {
    console.log("A");
    });
    console.log("B");
    // can be AB or BA depending on myTask

    // promises
    myTask(1, 2).then(() => {
    console.log("A");
    })
    console.log("B");
    // always BA

    这使代码更易于推理,但也意味着当您实际依赖第二行为时,promise将无济于事。

    (Read up more on Promises!)

    初始点

    好的,让我们回到您的代码。首先,让我用一个虚拟的异步函数替换 ogs,以便我们可以在不联网的情况下处理一些代码:
    var async = require('async');

    function ogs(param, callback) {
    let value = ["ogs", param];
    setTimeout(
    () => callback(null, value),
    20);
    }

    // global variables
    var param1 = {url: 'http://www.google.com/'};
    var param2 = {url: 'https://www.yahoo.com/'};

    function function1(callback){
    ogs(param1, function(error, data1) {
    callback(null, data1);
    });
    }
    function function2(data1, callback){
    ogs(param2, function(error, data2) {
    callback(null, data1, data2);
    });
    }
    function function3(data1, data2, callback){
    console.log(data1);
    console.log("---------------");
    console.log(data2);
    }

    (function temp() {
    async.waterfall([function1, function2, function3],
    function(err, result){
    console.log(result);
    console.log(err);
    if(err) console.log(err);
    }
    );
    })();

    让我们尝试这些 promise 的事情

    等效于 ogs,它返回一个promise而不是进行回调可能看起来像:
    function ogs(param, callback) {
    // return a promise that resolves after 20ms
    return new Promise((resolve, reject) => {
    setTimeout(() => {
    let value = ["ogs", param];
    resolve(value);
    }, 20);
    });
    }

    由于 ogs现在返回了一个promise,因此可以在每个 function中直接使用它:
    function function1(){
    return ogs(param1); // call async task, obtain the promise for its result and return it directly
    }
    function function2() {
    return ogs(param2);
    }
    function function3(data1, data2){
    console.log(data1);
    console.log("---------------");
    console.log(data2);
    }

    如果您想在中间添加一些日志记录,这也很容易:
    function function2() {
    return ogs(param2).then(data2 => {
    console.log("inside function2", data2);
    return data2;
    });
    }

    现在,每个步骤都是一个返回 promise 的异步任务,让我们将它们连接在一起!最简单的方法是直接使用 Promise.then:
    (function temp() {
    function1().then(data1 => {
    return function2().then(data2 => {
    return function3(data1, data2);
    });
    }).catch(error => {
    console.error("There was a problem:", error);
    })
    })();

    这将运行 function1,并在完成后将结果传递给 function2,然后将两个结果均传递给 function3

    并行运行

    可是等等! function2甚至不需要等待 function1完成。这是两个单独的请求。我们可以立即启动它们。
    (function temp() {
    let data1Promise = function1();
    let data2Promise = function2();
    Promise.all([data1Promise, data2Promise]).then(([data1, data2]) => {
    return function3(data1, data2);
    }).catch(error => {
    console.error("There was a problem:", error);
    })
    })();
    Promise.all接受一个promise数组,并返回一个promise,该promise用结果数组进行解析。我们从数组中解压缩这些结果,并将其传递给 function3

    并行运行网络请求应该可以使您的应用运行得更快。赢!

    现在回到您原来的问题:

    如何摆脱全局变量?

    我们已经完全控制了 function1function2的签名,所以让我们使用它吧!让我们让这些函数将param作为参数,而不是查看全局变量。像这样:
    function function1(param){
    return ogs(param);
    }
    function function2(param) {
    return ogs(param, {"some other options": true});
    }

    这些功能现在看起来 super 相似!也许您可以只使用一个(或者直接将它们放下并直接调用 ogs?)

    删除全局变量之后,我们的代码现在如下所示:
    (function temp() {
    let param1 = {url: 'http://www.google.com/'};
    let param2 = {url: 'https://www.yahoo.com/'};
    let data1Promise = function1(param1);
    let data2Promise = function2(param2);
    Promise.all([data1Promise, data2Promise]).then(([data1, data2]) => {
    return function3(data1, data2);
    }).catch(error => {
    console.error("There was a problem:", error);
    })
    })();

    但是我真的需要我的功能按顺序运行!

    如果没有 function2的结果 function1实际上无法启动怎么办?
    function function1(param) {
    return ogs(param);
    }

    function function2(data1, param) {
    return ogs(param2, {"some other options": data1});
    }

    我们可以使用嵌套的 then恢复到第一个版本,但是我们也可以尝试一些更简洁的方法:
    (function temp() {
    let param1 = {url: 'http://www.google.com/'};
    let param2 = {url: 'https://www.yahoo.com/'};
    let data1Promise = function1(param1);
    let data2Promise = data1Promise.then(data1 => function2(data1, param2)); // !
    Promise.all([data1Promise, data2Promise]).then(([data1, data2]) => {
    return function3(data1, data2);
    }).catch(error => {
    console.error("There was a problem:", error);
    })
    })();

    async.waterfall有何不同?
    waterfall要求您以某种方式编写函数,以便它们使用下一步所需的所有信息来调用 callback。流程如下所示:
    function1
    -> (data1)
    function2
    -> (data1, data2)
    function3

    想象一下,如果您必须链接10个调用而不是2个...基本上,第2步需要知道第3、4、5、6步可能需要什么。

    有了promise,您可以通过从每个任务返回一个数组来做同样的事情,但是您可以做得更好:

    不再需要用ogsfunction1 来包装 function2,因为您可以执行以下操作:
    Promise.all([ogs(...), ogs(...), ogs(...)]).then(allResults)

    一切都将收集到一个数组中。

    非常相关的阅读: Bluebird's Promise.all() method when one promise is dependent on another

    但是我的API无法返回 promise !

    我希望我现在能兑现您的 promise ,但是您仍然会坚持以下签名:
    ogs(options, function (err, results) {...})

    我们想将其转换为:
    ogsAsync(options) -> Promise

    它很简单,可以使用Promise构造函数手动完成:
    function ogsAsync(options) {
    return new Promise((resolve, reject) => {
    ogs(options, (err, results) => {
    if (err) {
    reject(err);
    } else {
    resolve(results);
    }
    });
    });
    }

    但是您可能不需要,因为是 looks like your library already returns a promise,因此您可以直接调用 osg(options)- ,它已经返回了promise 。耶!

    但是,以防万一您必须使用尚不提供 promise 的库(例如 redis或许多 node标准库), Bluebird提供了一个不错的实用程序,可以自动将回调样式的任务包装为 promise 样式的任务。

    希望对您有所帮助!

    关于javascript - 了解Node.JS使用async.waterfall如何执行外部功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38526996/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com