NodeJS实现同步的方法


Posted in NodeJs onMarch 02, 2019

NodeJS被打上了单线程、非阻塞、事件驱动…..等标签。

在单线程的情况下,是无法开启子线程的。经过了很久的研究,发现并没有thread函数!!!但是有时候,我们确实需要“多线程”处理事务。nodeJS有两个很基础的api:setTimeout和setInterval。这两个函数都能实现“异步”。

nodeJS的异步实现:nodeJS有一个任务队列,在使用setInterval函数的时候,会每隔特定的时间向该任务队列增加任务,从而实现“多任务”处理。但是,“特定的时间”不代表是具体的时间,也有可能是会大于我们设定的时间,也有可能小于。

我们跑跑下面代码块

setInterval(function() {
  console.log(new Date().getTime());
}, 1000);

输出的结果如下:

1490531390640
1490531391654
1490531392660
1490531393665
1490531394670
1490531395670
1490531396672
1490531397675
......

我们可以看到,所有的时间间隔都是不一样的。时间的偏移不仅包含了间隔的1s,还包含了console.log()的耗时,以及new Date()的耗时。在大量的数据统计下,时间间隔近似于1s。

问题来了,setInterval是能实现多任务的效果,但是怎样才能实现任务之间的同步操作呢?这里实现的方法是通过回调函数实现的。

function a(callback) {
  // 模拟任务a耗时
  setTimeout(function() {
    console.log("task a end!");
    // 回调任务b
    callback();
  }, 3000);
};
function b() {
  setTimeout(function() {
    console.log("task b end!");
  }, 5000);
}
a(b);

这里举了一个很简单的例子,就是将b方法的实现赋值给a方法的callback函数从而实现函数回调,但是会有个问题。假设a方法依赖于b方法,b方法依赖于c方法,c方法依赖于d方法…..也就意味着每个方法的实现都需要持有上一个方法的实例,从而实现回调。

function a(b, c, d) {
  console.log("hello a");
  b(c, d);
};
function b(c, d) {
  console.log("hello b");
  c(d);
};
function c(d) {
  console.log("hello c");
  d()
};
function d() {
  console.log("hello d");
};
a(b, c, d);

输出结果

hello a
hello b
hello c
hello d

如果回调函数写的多了,会造成代码特别特别恶心。

如果有类似于sync的函数能让任务顺序执行就更好了。终于找到了async这个库

$ npm instanll async

async = require("async");
a = function (callback) {
  // 延迟5s模拟耗时操作
  setTimeout(function () {
    console.log("hello world a");
    // 回调给下一个函数
    callback(null, "function a");
  }, 5000);
};
b = function (callback) {
  // 延迟1s模拟耗时操作
  setTimeout(function () {
    console.log("hello world b");
    // 回调给下一个函数
    callback(null, "function b");
  }, 1000);
};
c = function (callback) {
  console.log("hello world c");
  // 回调给下一个函数
  callback(null, "function c");
};
// 根据b, a, c这样的顺序执行
async.series([b, a, c], function (error, result) {
  console.log(result);
});

注释基本能够很好的理解了,我们看看输出

hello world b
hello world a
hello world c
[ 'function b', 'function a', 'function c' ]

上面的基本async模块的实现的如果了解更多关于async模块的使用,可以查询官方文档

其实nodeJS基本api也提供了异步实现同步的方式。基于Promise+then的实现

sleep = function (time) {
  return new Promise(function () {
    setTimeout(function () {
      console.log("end!");
    }, time);
  });
};
console.log(sleep(3000));

输出结果为:

Promise { <pending> }
end!

可以看出来,这里返回了Promise对象,直接输出Promise对象的时候,会输出该对象的状态,只有三种:PENDING、FULFILLED、REJECTED。字面意思很好理解。也就是说Promise有可能能实现我们异步任务同步执行的功能。我们先用Promise+then结合起来实现异步任务同步操作。

sleep = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      console.log("start!");
      resolve();
    }, 1000);
  })
    .then(function () {
      setTimeout(function () {
        console.log("end!");
      }, 2000);
    })
    .then(function () {
      console.log("end!!");
    })
};
console.log(sleep(1000));

输出结果:

Promise { <pending> }
start!
end!!
end!

在new Promise任务执行完后,调用了resolve才会执行所有的then函数,并且这些then函数是异步执行的。由输出结果可以知道。(如果所有then是顺序执行的应该是end! -> end!!)。但是上述也做到了两个异步任务之间顺序执行了。

不过,还有更加优雅的方式:使用async+await。

display = function(time, string) {
  return new Promise(function (resovle, reject) {
    setTimeout(function () {
      console.log(string);
      resovle();
    }, time)
  });
};
// 执行顺序:b a c
fn = async function () {
  // 会造成阻塞
  await display(5000, "b");
  await display(3000, "a");
  await display(5000, "c");
}();

输出结果:

b
a
c

由于这里时间输出比较尴尬,只能通过我们来感知,本人通过个人“感知”知道了在display b过度到display a的时候大概用了3s,再过度到display c的时候大概用了5s

这里需要声明的是:才开始正式的学习nodeJS。在学习的过程中,做的笔记,很多概念与理解可能会错误,如果错误,欢迎纠正。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

NodeJs 相关文章推荐
NodeJS url验证(url-valid)的使用方法
Nov 18 NodeJs
基于NodeJS的前后端分离的思考与实践(六)Nginx + Node.js + Java 的软件栈部署实践
Sep 26 NodeJs
Nodejs Stream 数据流使用手册
Apr 17 NodeJs
NodeJS创建最简单的HTTP服务器
May 15 NodeJs
手把手教你把nodejs部署到linux上跑出hello world
Jun 19 NodeJs
nodejs简单读写excel内容的方法示例
Mar 16 NodeJs
Nodejs 发布自己的npm包并制作成命令行工具的实例讲解
May 15 NodeJs
Nodejs中获取当前函数被调用的行数及文件名详解
Dec 12 NodeJs
nodejs实现用户登录路由功能
May 22 NodeJs
在NodeJs中使用node-schedule增加定时器任务的方法
Jun 08 NodeJs
浅谈vue websocket nodeJS 进行实时通信踩到的坑
Sep 22 NodeJs
浅谈Node的内存泄露问题
May 06 NodeJs
PHPStorm中如何对nodejs项目进行单元测试详解
Feb 28 #NodeJs
Nodejs对postgresql基本操作的封装方法
Feb 20 #NodeJs
深入理解nodejs搭建静态服务器(实现命令行)
Feb 05 #NodeJs
Nodejs实现的操作MongoDB数据库功能完整示例
Feb 02 #NodeJs
基于Koa(nodejs框架)对json文件进行增删改查的示例代码
Feb 02 #NodeJs
用Electron写个带界面的nodejs爬虫的实现方法
Jan 29 #NodeJs
NVM安装nodejs的方法实用步骤
Jan 16 #NodeJs
You might like
虹吸壶煮咖啡26个注意事项
2021/03/03 冲泡冲煮
php ignore_user_abort与register_shutdown_function 使用方法
2009/06/14 PHP
浅谈PHP进程管理
2019/03/08 PHP
javascript学习笔记(九)javascript中的原型(prototype)及原型链的继承方式
2011/04/12 Javascript
原生js的弹出层且其内的窗口居中
2014/05/14 Javascript
form+iframe解决跨域上传文件的方法
2016/11/18 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
2017/03/08 Javascript
Javascript ES6中数据类型Symbol的使用详解
2017/05/02 Javascript
利用Javascript获取选择文本所在的句子详解
2017/12/03 Javascript
vue-scroller记录滚动位置的示例代码
2018/01/17 Javascript
使用vue-router设置每个页面的title方法
2018/02/11 Javascript
实例分析Array.from(arr)与[...arr]到底有何不同
2019/04/09 Javascript
TypeScript开发Node.js程序的方法
2019/04/30 Javascript
vue+element实现表格新增、编辑、删除功能
2019/05/28 Javascript
微信小程序入口场景的问题集合与相关解决方法
2019/06/26 Javascript
使用JS监听键盘按下事件(keydown event)
2019/11/07 Javascript
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
[01:44]Ti10举办地公布
2019/08/25 DOTA
[31:55]完美世界DOTA2联赛循环赛 IO vs GXR BO2第一场 11.04
2020/11/05 DOTA
python3新特性函数注释Function Annotations用法分析
2016/07/28 Python
python ipset管理 增删白名单的方法
2019/01/14 Python
python框架flask入门之路由及简单实现方法
2020/06/07 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
在pytorch中动态调整优化器的学习率方式
2020/06/24 Python
Python matplotlib图例放在外侧保存时显示不完整问题解决
2020/07/28 Python
Python常用扩展插件使用教程解析
2020/11/02 Python
世界上最大的各式箱包网络零售店:eBag
2016/07/21 全球购物
世界闻名的衬衫制造商:Savile Row Company
2018/07/30 全球购物
黄色火烈鸟:De Gele Flamingo
2019/03/18 全球购物
美国林业供应商:Forestry Suppliers
2019/05/01 全球购物
领导视察欢迎词
2014/01/15 职场文书
《小猪家的桃花树》教学反思
2014/04/11 职场文书
自愿解除劳动合同协议书
2014/09/11 职场文书
代领报检证委托书范本
2014/10/11 职场文书
商务英语求职信范文
2015/03/19 职场文书
2016年安全月活动总结
2016/04/06 职场文书