Javascript 防止通过参数调用双函数

Javascript 防止通过参数调用双函数,javascript,node.js,function,unique,Javascript,Node.js,Function,Unique,我在Node.js应用程序中有一个循环,它每秒从数据库1个请求中连续获取未处理的行 我从DB收到的每一行都将调用一个函数,该函数具有唯一的数字ID,并将DB的其他详细信息作为参数。一旦在该函数中处理了数据,数据库就会更新,并且该行被标记为已处理 function fetch() { db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) { if(r

我在Node.js应用程序中有一个循环,它每秒从数据库1个请求中连续获取未处理的行

我从DB收到的每一行都将调用一个函数,该函数具有唯一的数字ID,并将DB的其他详细信息作为参数。一旦在该函数中处理了数据,数据库就会更新,并且该行被标记为已处理

function fetch() {
  db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) {
    if(results.length > 0) {
        for(var i=0; i<results.length; i++)
            process(results[i].id, results[i].data);
    }
  });
}
var interval_fetch = setInterval(fetch, 1000);

function process(id, data) {
  // Process data
  db.query("UPDATE table SET processed=1 WHERE id="+id);
}
但是,在某些情况下,处理数据和更新数据库需要一秒钟以上的时间。在这种情况下,进程使用相同的参数调用了两次甚至更多次

在Node.js环境中,最简单的方法是什么,以确保使用某个ID参数同时只调用函数一次

是否有提供此功能且只需要两行或三行额外代码的软件包

解决方案不一定要防止多次调用该函数。如果我能够检查进程内部,如果它已经被某个id调用,我也可以在数据被处理两次之前在那里结束它

var in_progress = {}; // Object that contains the IDs

function fetch() {
  db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) {
    if(results.length > 0) {
        for(var i=0; i<results.length; i++)
            process(results[i].id, results[i].data);
    }
  });
}
var interval_fetch = setInterval(fetch, 1000);

function process(id, data) {
  if(in_progress.hasOwnProperty(id)) { // Check if ID is in progress
    console.log("ID "+id+" in progress - do nothing");
    return;
  } else {
    in_progress[id] = true; // Insert ID into object

    // Process data here, then run below query

    db.query("UPDATE table SET processed=1 WHERE id="+id, function() {
      // Remove ID from object once DB is updated - Timeout to make sure nothing can overlap with the fetch function
      setTimeout(function(){ delete in_progress[id]; }, 1000); 
    });
  }
}
是否有提供此功能且只需要两行或三行额外代码的软件包

是的:

此外,所有promise库都应该提供这种开箱即用的功能。还有发电机

但是我建议改变你的编码方式,而不是使用它们。setTimeout而不是setInterval可以通过以下方式消除整个问题:

function fetch() {
  db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) {
    if(results.length > 0) {
       for(var i=0; i<results.length; i++)
          process(results[i].id, results[i].data)
    }
    setTimeout(fetch, 1000)
  })
}
var interval_fetch = setTimeout(fetch, 1000)

function process(id, data) {
  // Process data
  db.query("UPDATE table SET processed=1 WHERE id="+id)
}

简单地说,在作业完成后设置超时

function fetch() {
  db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) {
    if(results.length > 0) {
        for(var i=0; i<results.length; i++)
            process(results[i].id, results[i].data);
    }
  });
}
setTimeout(fetch, 1000);

function process(id, data) {
  // Process data
  db.query("UPDATE table SET processed=1 WHERE id="+id, function() {
    setTimeout(fetch, 1000);
  });

}

今天早上,我得到了一个相对简单的解决方案。因此,我要回答我自己的问题

我只是维护一个对象,其中包含当前正在处理且尚未在数据库中更新的所有ID。每次调用进程时,我都会检查ID当前是否正在进行,如果适用,则会取消,然后再对数据进行两次处理

var in_progress = {}; // Object that contains the IDs

function fetch() {
  db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) {
    if(results.length > 0) {
        for(var i=0; i<results.length; i++)
            process(results[i].id, results[i].data);
    }
  });
}
var interval_fetch = setInterval(fetch, 1000);

function process(id, data) {
  if(in_progress.hasOwnProperty(id)) { // Check if ID is in progress
    console.log("ID "+id+" in progress - do nothing");
    return;
  } else {
    in_progress[id] = true; // Insert ID into object

    // Process data here, then run below query

    db.query("UPDATE table SET processed=1 WHERE id="+id, function() {
      // Remove ID from object once DB is updated - Timeout to make sure nothing can overlap with the fetch function
      setTimeout(function(){ delete in_progress[id]; }, 1000); 
    });
  }
}

这正是我想要的。我甚至可以加快提取间隔,开始处理数据库中的所有新数据,而不会有明显的延迟。仍然没有任何东西会被处理两次。

我相信setInterval的目的是因为他希望作业每秒重复一次,而不是因为他只希望作业发生一次。这就是为什么我在那里添加了一个递归setTimeout调用。我感谢您的回复。包部分实现了我想要的功能,但是setTimeout建议没有。请看我自己的答案。谢谢你的回答。不幸的是,这并不像我想的那样有效。如果查询返回具有不同数据的多行,则该过程称为具有不同参数的多次。一旦完成,每个人将设置一个新的超时。如果一个函数调用在0.1秒后完成,另一个函数调用在5秒后完成,则会再次处理较慢的函数调用。
var in_progress = {}; // Object that contains the IDs

function fetch() {
  db.query("SELECT id, data FROM table WHERE processed=0 ORDER BY id ASC", function(err, results) {
    if(results.length > 0) {
        for(var i=0; i<results.length; i++)
            process(results[i].id, results[i].data);
    }
  });
}
var interval_fetch = setInterval(fetch, 1000);

function process(id, data) {
  if(in_progress.hasOwnProperty(id)) { // Check if ID is in progress
    console.log("ID "+id+" in progress - do nothing");
    return;
  } else {
    in_progress[id] = true; // Insert ID into object

    // Process data here, then run below query

    db.query("UPDATE table SET processed=1 WHERE id="+id, function() {
      // Remove ID from object once DB is updated - Timeout to make sure nothing can overlap with the fetch function
      setTimeout(function(){ delete in_progress[id]; }, 1000); 
    });
  }
}