用NodeJs实现延迟调用,规避定时任务的闭包问题
很多人在用NodeJs的setTimeout(callback, delay[, arg][, ...])编写定时任务时,习惯上直接操作callback外部的对象object(闭包的特点)。这样做有一个隐患,就是当callback真正执行的时候,外部对象object可能已经被销毁了(比如执行了自定义的销毁方法),导致对object进行的处理结果出现了很大的偏差,程序甚至有可能出现异常而退出。
解决这个问题其实很简单,我们只需要在callback回调中重新通过某种方式获取该对象,检查一下该对象是否已被销毁,即可避免上面描述的问题。但是,当程序中需要很多这样的需求时,并且是一个团队在合作写代码,这样就很难避免上述情况的发生。为了规避定时任务的闭包问题,我写了一个延迟调用类,代码如下:
/**
* script: delayCall.js
* description: 延迟调用,规避定时任务的闭包问题
* authors: alwu007@sina.cn
* date: 2016-04-19
*/ var util = require('util');
var PQueue = require('./pqueue').PQueue; /**
* 延迟调用类
* @param search_func 对象查找函数
*/
var DelayCall = exports.DelayCall = function(search_func) {
//延迟调用序号
this._call_seq = 0;
//延迟调用映射
this._call_map = {};
//延迟调用队列
this._call_queue = new PQueue(DelayCall.compare);
//对象查找方法
this._search_func = search_func; //设置间隔定时器。FIXME:可以改为在框架的心跳机制中去执行run方法
//注:setTimeout不支持修改系统时间
this._interval_id = setInterval(() => {
this.run();
}, 1000);
}; //比较延迟调用
DelayCall.compare = function(call1, call2) {
var time_diff = call1.exec_time - call2.exec_time;
if (time_diff) {
return time_diff;
} else {
return call1._call_id - call2._call_id;
}
}; //延迟调用序号自增
DelayCall.prototype._addSequence = function() {
return ++ this._call_seq;
}; /**
* 延迟调用
* @param id 对象查找方法_search_func根据id查找出调用者对象
* @param method_name 调用者对象上要延迟调用的方法名
* @param params 要延迟调用的方法参数
* @param delay 延迟时间,单位秒
*/
DelayCall.prototype.call = function(id, method_name, params, delay) {
var call_id = this._addSequence();
var exec_time = Date.now() + delay * 1000;
var call_elem = {
_call_id: call_id,
id: id,
method_name: method_name,
params: params,
delay: delay,
exec_time: exec_time,
_canceled: false,
};
this._call_queue.enQueue(call_elem);
this._call_map[call_id] = call_elem;
return call_id;
}; //取消延迟调用
DelayCall.prototype.cancelCall = function(call_id) {
var call_elem = this._call_map[call_id];
if (call_elem) {
delete this._call_map[call_id];
call_elem._canceled = true;
}
}; //运转一次
DelayCall.prototype.run = function() {
var now = Date.now();
var pqueue = this._call_queue;
var search_func = this._search_func;
var call_elem = pqueue.getHead();
while (call_elem) {
if (call_elem._canceled) {
pqueue.deQueue();
} else {
if (now < call_elem.exec_time) {
break;
} else {
//从队列和映射中删除
pqueue.deQueue();
delete this._call_map[call_elem._call_id];
//执行对象的方法
var obj = search_func(call_elem.id);
if (obj && typeof obj[call_elem.method_name] == 'function') {
obj[call_elem.method_name](call_elem.params);
}
}
}
call_elem = pqueue.getHead();
}
};
PQueue的实现请参考我的饿另一篇博文:用NodeJs实现优先级队列PQueue
用NodeJs实现延迟调用,规避定时任务的闭包问题的更多相关文章
- 【Unity3D】Invoke,InvokeRepeating ,Coroutine 延迟调用,周期性调用
Invoke和InvokeRepeating方法,可以实现延迟调用,和周期调用 第一个是执行一次,第二个是重复执行 void Invoke(string methodName, float time) ...
- xcode UIImageView创建、图片加载、 音频文件播放、 延迟调用
代码创建 /** 创建UIImageView */ UIImageView * imageView=[[UIImageView alloc]init]; /** 设置尺寸位置 */ imageView ...
- 延迟调用或多次调用第三方的Web API服务
当我们调用第三方的Web API服务的时候,不一定每次都是成功的.这时候,我们可能会再多尝试几次,也有可能延迟一段时间再去尝试调用服务. Task的静态方法Delay允许我们延迟执行某个Task,此方 ...
- ios 延迟调用 && UIImageView && UILabel && UISegmentedControl && UISwitch && UISlider
// // ViewController.m // UI_Lesson3 // // Created by archerzz on 15/8/13. // Copyright (c) 2015 ...
- 17_defer(延迟调用)关键字的使用
1.defer是延迟调用关键字,只能在函数内部使用 2.总是在main函数结束前调用(和init用法相对) 3.如果有多个defer 遵循先进后出的原则 4.和匿名函数同时使用时,如果匿名函数带有参数 ...
- Go语言系列开发之延迟调用和作用域
Hello,各位小伙伴大家好,我是小栈君,最近一段时间我们将继续分享关于go语言基础系列,当然后期小栈君已经在筹划关于java.Python,数据分析.人工智能和大数据等相关系列文章.希望能和大家一起 ...
- defer 延迟调用
1. 延迟调用 defer 的用法很简单,只要在后面跟一个函数的调用,就能实现将这个 xxx 函数的调用延迟到当前函数执行完后再执行. defer xxx() 这是一个很简单的例子,可以很快帮助 ...
- 在Nodejs中如何调用C#的代码
最近需要在Nodejs中用到C#的代码,从网上了解到可以采用Edgejs来实现Nodejs与C#的代码交互, 直接复制网上的代码运行总是出各种错,填了不少坑,现在把自己的案例代码大致整理一下,方便以后 ...
- Twisted 延迟调用
延迟(defer)是twisted框架中实现异步的编程体系,使程序设计可以采用事件驱动的机制 1.基本使用 defer可以看作一个管理回调函数的对象,可以向该对象添加需要的回调函数同时也可以指定该组函 ...
随机推荐
- hbase rowkey设计的注意事项
充分利用有序性 1.1 如果要scan操作,且不是很频繁,可以利用rowkey的有序性将需要一起扫描的数据放到一起.例如直接用时间戳.这样就可以按时间scan了.这个只要是简单的全表扫描都行. 1.2 ...
- SET NOCOUNT用法
当 SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数). 当 SET NOCOUNT 为 OFF 时,返回计数. 如果存储过程中包含的一些语句并不返回 ...
- Spring 配置方式
1.bean的配置方式:通过全类名(反射),通过工厂方法(静态工厂方法&实例工厂方法).FactoryBean. 2.静态工厂方法:直接调用某一个类的静态方法就可以返回bean的实例. cla ...
- ASP.NET MVC 增强Convert用法+【分页2】
[分页2] public dynamic PageQuery() { : : ; i < data.Length; i++) ...
- CH Round #45 能量释放
能量释放 CH Round #45 - alan有一些陷阱 III 题目描述 alan得到一块由个能量晶体构成的矿石,对于矿石中的每一个能量晶体,如果用化学物质刺激某一个能量晶体,就能使它释放能量. ...
- 【转】eclipse android 设置及修改生成apk的签名文件 -- custom debug keystore
原文网址:http://hold-on.iteye.com/blog/2064642 android eclipse 设置及修改生成apk的签名文件 1. 问题: 平时在使用eclipse进行andr ...
- C# Login方法
public static bool User_Login(string url, string uname, string password, out string[] userInfo) { st ...
- python 零散记录(六) callable 函数参数 作用域 递归
callable()函数: 检查对象是否可调用,所谓可调用是指那些具有doc string的东西是可以调用的. 函数的参数变化,可变与不可变对象: 首先,数字 字符串 元组是不可变的,只能替换. 对以 ...
- JavaScript---网络编程(5)-自定义对象Json、Dom模型概念讲解
这节博客主要讲解Dom模型概念~和JSON的简单介绍 首先,还是先上out.js的代码: function println(param){ document.write(param+"< ...
- vijosP1006 晴天小猪历险记之Hill
vijosP1006 晴天小猪历险记之Hill 链接:https://vijos.org/p/1006 [思路] 图上DP. 这个题的递推顺序是关键.先从上一行得到最小值,然后从本行比较最小值,注意本 ...