通过回调在JavaScript中管理队列

use*_*192 10 javascript callback

我正在使用JavaScript来管理队列的页面.我的挑战是我的代码有嵌套回调.嵌套的回调让我对队列的范围感到困惑.目前,我有以下内容:

function MyApp() {}
module.exports = MyApp;

MyApp.myQueue = [];
MyApp.queueIsLocked = false;

MyApp.enqueue = function(item, onSuccess, onFailure) {
  if (!MyApp.queueIsLocked) {
    MyApp.queueIsLocked = true;        
    MyApp.myQueue.push(item);
    MyApp.queueIsLocked = false;

    item.send(   
      function() {
        console.log('item: ' + item.id);

        MyApp.queueIsLocked = true;                      
        MyApp.findItemById(item.id,
          function(index) {
            if (index !== -1) {
              MyApp.myQueue.splice(index, 1);
              MyApp.queueIsLocked = false;

              if (onSuccess) {
                onSuccess(item.id);
              }
            }
          }
        );
      },
      function() {
        alert('Unable to send item to the server.');
        if (onFailure) {
          onFailure();
        }
      }
    );
  }
};

MyApp.findItemById = function(id, onComplete) {
  var index = -1;
  if (MyApp.queueIsLocked) {
    setTimeout(function() {
      // Attempt to find the index again.
    }, 100);
  } else {
    MyApp.queueIsLocked = true;
    for (var i=0; i<MyApp.myQueue.length; i++) {
      if (MyApp.myQueue[i].id === id) {
        index = i;
        break;
      }
    }
  }

  if (onComplete) {
    onComplete(index);
  }
};
Run Code Online (Sandbox Code Playgroud)

该send函数根据细节的不同表现item.有时该项目将被发送到一台服务器.有时,它会被发送到多个服务器.无论哪种方式,我不知道什么时候该项目将被"发送".出于这个原因,我正在使用回调来管理队列.当项目完成"发送"时,我想将其从队列中删除.我需要使用超时或间隔来检查队列是否被锁定.如果它未锁定,我想从队列中删除该项目.这项检查增加了另一层次的嵌套,令我感到困惑.

我的挑战是,我不相信索引的范围像我预期的那样工作.我觉得我得到了比赛条件.我的基础是我写了下面的Jasmine测试:

describe('Queue', function() {
  describe('Approach 1', function() {
    it('should do something', function() {
      MyApp.enqueue({id:'QRA', text:'Test A'});
    });
  });

  describe('Approach 2', function() {
    it('should successfully queue and dequeue items', function() {
      MyApp.enqueue({id:'WX1', text:'Test 1'});
      MyApp.enqueue({id:'QV2', text:'Test 2'});
      MyApp.enqueue({id:'ZE3', text:'Test 3'});
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

当我执行测试时,我在控制台窗口中看到以下内容:

item: QRA index: 1
item: WX1 index: 2
item: QV2 index: 3
item: ZE3 index: 4
Run Code Online (Sandbox Code Playgroud)

它就像物品没有像我期望的那样出类拔萃.在我管理队列的方法中,我是否会偏离基础?我究竟做错了什么?

谢谢你的帮助.

Gre*_*ant 10

以下是您需要思考并回答自己的意图和设计的一些问题:

  1. 听起来,队列代表您尝试发送到服务器的项目.您正在向需要发送的队列添加项目,并在成功发送后将其从队列中删除.
  2. 您是否希望您的代码同时发送多个项目?例如,项目A被添加到队列中,然后发送.在A的异步发送完成之前,项目B被添加到列表中.代码是否应该在项目A的发送完成之前发送项目B?根据您的代码,听起来像是的.

看起来你本身并不需要/需要一个队列,因为你想要一个列表来跟踪哪些项目正在被发送过程中."队列"意味着正在以某种FIFO顺序处理对象.

如果您只想基于id跟踪项目,则可以使用对象.例如:

MyApp.items = {};
MyApp.addItem = function(item){
  MyApp.items[item.id] = item;
  item.send(
    function(){ // success
      MyApp.removeItem(item.id)
    }
  );
}
MyApp.removeItem = function(id){
  delete MyApp.items[id];
  onSuccess(id);
}
Run Code Online (Sandbox Code Playgroud)

另外,我认为您不需要锁定队列.Javascript是单线程的,因此您永远不会遇到代码的两个部分同时尝试在队列上运行的情况.当ajax调用异步完成时,在当前正在执行的任何其他代码完成之前,您的回调代码实际上不会执行.