资讯专栏INFORMATION COLUMN

JavaScript 并行和串行任务/流程控制 的实现

bladefury / 412人阅读

摘要:并行和串行任务在里面异步是一个很重要的知识点的异步跟其他语言不一样他是根据执行回调的方式来实现的。在之前,执行任务想要实现这个流程控制只能通过依赖来实现或者通过而在之后官方自己实现了和来实现。

JavaScript 并行和串行任务

在 JavaScript 里面 异步 是一个很重要的知识点,JS 的异步跟其他语言不一样, 他是根据执行回调的方式来 实现的。由于我们不知道异步什么时候会执行完,让一组异步任务顺序执行就显得很重要了,这个时候我们就需要 流程控制 ,这种流程控制有两种 串行(series)并行(parallel)

实际开发中也许你在 JS 中很少接触到这个 并行串行 ,但是如果你接触过 gulp 我相信你应该对这个概念并不陌生.因为在 gulp 里面编写 task 到处充斥着这种异步执行。在 gulp(4.0)之前,执行任务想要实现这个流程控制只能通过 依赖 来实现或者通过 run-sequence,而在 gulp(4.0)之后官方自己实现了 gulp.seriesgulp.parallel 来实现。如果之前没有接触过 gulp 有兴趣的可以了解下(虽然现在是 Webpack 的世界~~~)

而如果对于 串行并行 有所接触的话,一般都会使用一个叫 nimble,但是我个人对于这个库里面实现 并行 功能是有疑问的.疑问点在于他不是按照我想象的工作方式工作

串行的简单实现

串行的实现有点像 Koa 里面对于中间件的实现。通过一个 next 函数来触发下一个函数的执行。

// 或者使用reduce
let series = function(arr) {
  let index = 0;
  let next = function() {
    if (index >= arr.length) {
      return;
    }
    arr[index](next);
    index++;
  };
  next();
};

这是一个基本的实现逻辑,实现的方式有点粗糙,其实我们每次取出的函数的方式可以进行一个优化,不需要中间变量 index 来记录当前的执行函数,而是通过 Array.prototype.shift 去取数组里面的函数用来执行

let series = function(arr) {
  let next = function(data) {
    let fn = arr.shift();
    if (!fn) {
      return;
    }
    fn(next,data);
  };
  next();
};

// 使用方法
let str = "";
series([
  function(next) {
    setTimeout(function() {
      str = "Hello"
      next(str);
    }, 100);
  },
  function(next,data) {
    setTimeout(function() {
      str += "World"
      console.log(str)
      console.log(data);
      next();
    });
  }
]);
并行的简单实现

刚刚在上面提到过,我对于 nimble 中 并行的实现是有疑问的,他并没有按照我上面的 图片执行,少了我觉得很重要的一步 并行应该又一个最终的函数,这个函数要等其他函数执行完毕才会执行

假设我有三个需要并行执行的函数 fn1,fn2,fn3。 当这三个函数执行之后应该需要在时间最晚的函数内执行一个最终的函数,来 处理一些依赖逻辑。下面是我个人的 简单实现代码

let parallel = function(arr, finnaly) {
  let fn,
    index = 0;
  let statusArr = Array(arr.length)
    .fill()
    .map(() => ({
      isActive: false,
      data: null
    }));
  let isFinished = function() {
    return statusArr.every(item => {
      return item.isActive === true;
    });
  };
  let resolve = function(index) {
    return function(data) {
      statusArr[index].data = data;
      statusArr[index].isActive = true;
      let isFinish = isFinished();
      if (isFinish) {
        let datas = statusArr.map(item => {
          return item.data;
        });
        finnaly(datas);
      }
    };
  };
  while ((fn = arr.shift())) {
    // 给resolve函数追加参数,可以使用bind函数实现,这里使用了柯里化
    fn(resolve(index));
    index++;
  }
};

// 使用方法
let str = "";
parallel(
  [
    function(resolve) {
      setTimeout(function() {
        str = "Hello";
        resolve("Hello");
      }, 1000);
    },
    function(resolve) {
      setTimeout(function() {
        str += "World";
        resolve("World");
      }, 20);
    }
  ],
  function(datas) {
    console.log("finily", datas);
  }
);
关于其他

以上就是简单的 串行并行 实现的基本方案, 有一些地方用到了 ES6,希望读者不要介意。其实如果你是 面向ES6开发 的话。更简单的方式是用 Promise 的方案,甚至可以使用 async/awaitgenerator 这些高级方法,来使 异步 代码跟同步一样使用,使代码的可读性更高

// 并行
let datas = await Promise.all([
  new Promise(resolve => {
    setTimeout(resolve.bind(this,10), 1000);
  }),
  new Promise(resolve => {
    setTimeout(resolve.bind(this,12), 2000);
  })
])

// 串行
let data1 = await new Promise(resolve => {
  setTimeout(resolve.bind(this, 10), 1000);
})
let data2 = await new Promise(resolve => {
  setTimeout(resolve.bind(this, 12), 1000);
});

这样看起来是不是很简洁

ES6 大法好!!! ES6 大法好!!! ES6 大法好!!!

重要事情说三遍
相信你看出来了吧,这篇文章其实是来宣传ES6的,不过还是希望大家能了解一下底层的实现。另外有一篇 Promise的实现。写的相当好,极力推荐阅读一下

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107422.html

相关文章

  • 异步操作(一)概述

    摘要:回调函数指定了下一步操作。异步操作的流程控制参数为秒后返回结果上面代码的函数是一个异步任务,非常耗时,每次执行需要秒才能完成,然后再调用回调函数。 单线程模型同步任务和异步任务任务队列和事件循环异步操作的模式回调函数事件监听发布/订阅异步操作的流程控制串行执行并行执行并行与串行的结合 1.单线程模型指的是js只在线程运行,一个时间执行一个任务,其他任务排队。事实上是一个运行脚本的主线程...

    wemall 评论0 收藏0
  • js异同步

    摘要:完成请问应该如何安排操作流程上面代码采用个回调函数的嵌套,不仅写起来麻烦,容易出错,而且难以维护串行执行我们可以编写一个流程控制函数,让它来控制异步任务,一个任务完成以后,再执行另一个。 前言 回调地狱showImg(https://segmentfault.com/img/remote/1460000011554165?w=1000&h=710); js异步 Javascript 语...

    leanxi 评论0 收藏0
  • Nodejs异步流程框架async

    摘要:如果任何函数发生错误,会立刻执行回调函数,并返回错误信息若没有发生错误,则会再所有函数执行完毕之后用回掉函数将结果返回。 Async的简单介绍: Async是一个流程控制工具包,提供了直接而强大的异步功能。基于Javascript为Node.js设计,同时也可以直接在浏览器中使用。Async提供了大约20个函数,包括常用的map, reduce, filter, forEach等,异步...

    miya 评论0 收藏0
  • java高并发系列 - 第3天:有关并行两个重要定律

    摘要:阿姆达尔定律定律是计算机科学中非常重要的定律。它定义了串行系统并行化后的加速比的计算公式和理论上线。需要从根本上修改程序的串行行为,提高系统内可并行化的模块比重,在此基础上,合理增加并行处理器数量,才能以最小的投入,得到最大的加速比。 有关为什么要使用并行程序的问题前面已经进行了简单的探讨。总的来说,最重要的应该是处于两个目的。 第一,为了获得更好的性能; 第二,由于业务模型的需要,确...

    liaoyg8023 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<