这么让 js 回调按顺序执行?

function listenerA(eventValue) {
    // 查询数据库、写数据库等等操作
    dbObj.query(
      eventValue,
      function(err, results) {
          // 一些逻辑处理后写数据库
          dbObj.insert(
            eventValue,
            function(err) {
            }
          );
      }
    );
}

someObj.on('someEvent', listenerA);

代码大致如上,someObjdbObj 都是第三方库提供的对象,someEvent 是持续产生的事件,怎么确保按 someEvent 触发顺序来写数据库呢?

阅读 3.7k
4 个回答

1简单写个队列模型

const queue = {
  list: [],
  status: false,
  exec: (eventValue, next) => {
    listenerA(eventValue, next);    // 这里绑定成你自己的处理函数 参见3.
  },
  push: (eventValue) => {
    queue.list.push(eventValue);
    queue.start();
  },
  start: () => {
    if (!queue.status && queue.list.length) {
      queue.status = true;
      const params = queue.list.shift();
      queue.exec(params, () => {
        queue.status = false;
        queue.start();
      });
    }
  }
};

2现在触发事件不直接执行函数,而是推入队列

someObj.on('someEvent', queue.push);

3处理函数加个next回调,告知队列本次执行完毕了,开始执行下一条

function listenerA(eventValue, next) {
  // 查询数据库、写数据库等等操作
  dbObj.query(
    eventValue,
    function (err, results) {
      // 一些逻辑处理后写数据库
      dbObj.insert(
        eventValue,
        function (err) {
          next();    // 触发next才开始下一条执行
        }
      );
    }
  );
}

简单写的模型比较粗略,但是应该能跑,还要视实际情况自己完善

someObj触发的event可以传递自定义函数。可以在自定义函数中控制各任务的编排。如果只是按触发顺序的话这边工作量不多。只是增加到一个代办列表而已。普通的一个数组push进去就好了。
dbObj看到可以传递执行成功的回调。那么可以将其promise化 这样可以用async/await去保证一个内容执行完成后执行下一个任务。
做到这两点应该就能满足需求了。

const taskArr = []
let isRuning = false
const run = async () => {
  if(isRuning)return
  isRuning = true
  while (taskArr.length) {
    const eventValue = taskArr.shift()
    try {
      await new Promise((resolve, reject) => {
          dbObj.query(
            eventValue,
            function (err, results) {
              // 一些逻辑处理后写数据库
              dbObj.insert(
                eventValue,
                function (err) {
                  resolve()
                }
              );
            }
          );
      })
    } catch (e) {
      console.error(e)
    }
  }
  isRuning = false
}
function listenerA(eventValue) {
  taskArr.push(eventValue)
  run()
}

someObj.on('someEvent', listenerA);

可以试试动态绑定和解绑,触发事件时先解绑事件,执行完嵌套逻辑后再重新绑定,不知道你持续触发的事件是什么情况,如果不影响的话。

someObjdbObj 具体是什么库提供的对象呢,看下这个库有没有提供prmoiseAPI,有的话可以改写为:

async function listenerA(eventValue) {
    // 查询数据库、写数据库等等操作
    try {
         let result = await dbObj.query(eventValue);
         await  dbObj.insert(eventValue)
    } catch (e) {
      console.error(e)
    }
}

没有提供prmoiseAPI,使用其他把api转为prmoiseAPI,比如 util.promisify 或者birdblue的API,再照上面调用就好了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题