在 Javascript/Node 中运行函数数组的规范方法

Posted

技术标签:

【中文标题】在 Javascript/Node 中运行函数数组的规范方法【英文标题】:Canonical way to run an array of functions in Javascript/Node 【发布时间】:2017-10-31 01:01:05 【问题描述】:

我找到了两个方便的模块,称为 run-parallel 和 run-series 来运行数组函数并返回结果数组。

看着 Github 项目中很少有贡献者和明星,我想知道是否有一种规范的方式来完成这些任务而不是安装这些模块?

也许在 Node 或 ES6 中有一种本地方式可以做到这一点,我错过了?

【问题讨论】:

异步或同步函数? 请看我对类似问题的回答***.com/a/44253855/1464130 【参考方案1】:

示例

首先查看一些示例 - 滚动下方查看说明。

回调:

异步和采用 Node 样式回调的函数的示例:

async.parallel([
  (cb) => 
    setTimeout(() => 
      cb(null, 'one');
    , 200);
  ,
  (cb) => 
    setTimeout(() => 
      cb(null, 'two');
    , 100);
  ,
],
(err, results) => 
  if (err) 
    // there was an error:
    console.log('Error:', err);
    return;
  
  // we have ['one', 'two'] in results:
  console.log('Results:', JSON.stringify(results));
);

承诺:

使用返回承诺的函数的示例 - 使用 Bluebird 的 delay() 函数:

const  delay  = require('bluebird');

Promise.all([
  delay(200, 'one'),
  delay(100, 'two'),
]).then((results) => 
  // we have ['one', 'two'] in results:
  console.log('Results:', JSON.stringify(results));
).catch((err) => 
  // there was an error:
  console.log('Error:', err);
);

ES2017async/await:

使用异步/等待:

const  delay  = require('bluebird');

try 
  const results = await Promise.all([
    delay(200, 'one'),
    delay(100, 'two'),
  ]);
  // we have ['one', 'two'] in results:
  console.log('Results:', JSON.stringify(results));
 catch (err) 
  // there was an error:
  console.log('Error:', err);

我使用JSON.stringify() 明确说明results 中的数据格式是什么。

请注意,即使第一个值排在最后,仍会保留原始顺序。

最后一个示例必须在使用 async 关键字声明的函数内运行,或者像这样包装在 (async () => ... )() 中:

(async () => 
  try 
    const results = await Promise.all([
      delay(200, 'one'),
      delay(100, 'two'),
    ]);
    // we have ['one', 'two'] in results:
    console.log('Results:', JSON.stringify(results));
   catch (err) 
    // there was an error:
    console.log('Error:', err);
  
)();

生成器和协程:

在不支持 async/await 的情况下,您可以使用一些基于生成器的协程,例如来自 Bluebird 的协程:

const  delay, coroutine  = require('bluebird');

coroutine(function* () 
  try 
    const results = yield Promise.all([
      delay(200, 'one'),
      delay(100, 'two'),
    ]);
    // we have ['one', 'two'] in results:
    console.log('Results:', JSON.stringify(results));
   catch (err) 
    // there was an error:
    console.log('Error:', err);
  
)();

说明

有很多方法可以做到这一点,这完全取决于您要运行的函数类型。

如果您想运行传统的 Node 风格函数,将错误优先回调作为最后一个参数,那么并行或串行运行这些函数的最流行方法是 npm 上的 async 模块:

https://www.npmjs.com/package/async

在 ES6 中没有对类似的东西的内置支持,因为那些错误优先回调实际上是 Node 的东西,在 Node 之外的 javascript 中不是很流行。

ES6/ES7/ES8 朝着返回 Promise 的函数(而不是接受回调的函数)的方向发展,并且有一个新的 async/await 语法使它们看起来有点像同步,使用 try/catch 进行错误处理。

因此,Node 中最流行的组合接受回调的函数的方式是异步模块:

https://www.npmjs.com/package/async

使用 Promise 的一个流行模块是 Bluebird:

https://www.npmjs.com/package/bluebird

对于更高级的任务,有 Task.js:

https://github.com/mozilla/task.js

查看这些答案了解更多信息:

try/catch blocks with async/await node.js ~ constructing chained sequence of Promise resolves How to run Generator Functions in Parallel? node.js ~ constructing chained sequence of Promise resolves Using async/await + Bluebird to promisifyAll jQuery: Return data after ajax call success

【讨论】:

【参考方案2】:

请记住,函数可以像 JavaScript 中的任何其他对象一样被传递,所以实际上做这样的事情非常简单。

例如,要串联运行,您可以使用 map 通过执行每个函数来生成结果数组 - 像这样...

let functions = [
    function()  return 'abc'; ,
    function()  return 123; ,
    function()  return  key: 'value' ; 
];

let results = functions.map(fn => fn());

显然,您从使用这些库中获得的好处是好的 - 希望经过良好测试 - 可以在出现问题时进行处理等,但如果没有它们,完全有可能做到这一点。

【讨论】:

【参考方案3】:

您可以使用Array.prototype.map() 依次循环遍历数组中的所有函数,使用匿名函数执行数组中的每个函数作为参数。

使用Function.prototype.apply() 而不是直接调用函数,您可以将数组及其参数传递给每个函数。

示例

var functions = [
    function(x)return 3 * x,
    function(x)return 4 * x,
    function(x)return 8 * x,
    function(x)return 10 * x,
    function()return Array.prototype.map.call(arguments, function(name)
        return "Hello, " + name
    )
];

var results = functions.map(function(value, index) 
   return value.apply(value, this[index]);
, [[5], [1], [8], [8], ["Dolly", "major Tom"]]);

document.body.innerhtml = '<pre>' + JSON.stringify(results, null, '\t') +  '</pre>';

另见this Fiddle

【讨论】:

【参考方案4】:

结构取决于您要实现的内容。 :D

functions = ;

async function getArticle(id = 0) 
  // const result = await articles.get(id); get result of a db.
  const result =  id: 10, name: "apple" 
  if (result) return result;
  return false;


async function validatePermission(id = 0) 
  // const result = await users.get(id); get result of a db.
  const result =  id: 25 
  if (result) return result;
  return false;


functions.getArticle = async params => 
  const  userId, articleId  = params;
  
  const [validUser, article] = await Promise.all([
    validatePermission(userId),
    getArticle(articleId),
  ]);

  if (validUser === false || article === false) 
    return  status: 400, message: 'Error', data: [] 
  
  
  return  status: 200, message: 'Success', data: article ;

 

 const params =  userId: 25, articleId: 10 ;
 functions.getArticle(params)
  .then(result => 
    console.log(result);
  );

【讨论】:

一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决问题的原因,答案会更有帮助。

以上是关于在 Javascript/Node 中运行函数数组的规范方法的主要内容,如果未能解决你的问题,请参考以下文章

获取属于 JavaScript/Node js 中特定 ID 的数组对象的计数

如何在 JavaScript node.js 中将 xml 文件解析为数组

Javascript - Node.js - 防止函数的多次执行

如何使用 Node.js/JavaScript 合并两个按键值匹配的数组值

在Javascript(node.js,express.js,ejs)中访问服务器端变量[关闭]

javascript/node.js 中的 JSONP 解析