Javascript中的异步操作。

时间:2016-02-11 15:41:27

标签: javascript asynchronous

我正在创建一个React应用程序,它涉及对一些webapi REST服务的多次调用来完成我的工作。应用程序的一部分是一些请求的批准流程。可以使用包含以下内容的UI创建这些流的特定角色:

  1. 一个表,列出了按基数排序的过程步骤(即订单)。这些步骤还有演员和状态。
  2. 每行上的按钮以上/下排列
  3. 每行上的按钮以删除相应的行
  4. 添加新步骤的按钮。
  5. 我所做的是允许用户使用Javascript(主要是数组操作)进行更改,同时使用操作和相应数据填充actionbuffer数组。例如

    this.actionsBuffer.push({
            action: "ADD_STEP",
            data: next
        });
    

    当用户对此安排感到满意时,她可以按“接受”按钮。它的作用是迭代actionsBuffer数组并执行由action字段确定的相应REST服务。

    我知道我的描述可能看起来过于详细,但我希望您了解背景。

    问题: 我现在的问题是,由于调用是异步的,我如何保证操作将按此顺序执行。

    一些代码段:

    迭代并调用determineAction

    onAccept: function (e) {
            e.preventDefault();
            var self = this;
            //console.log("Gonna save:",JSON.stringify(this.state.workflow));
    
            var ret=null;
            // First we do actions in actionsBuffer
            for(var i=0;i<this.actionsBuffer.length;i++)
            {
                ret = self.determineAction(this.actionsBuffer[i]);
                if (ret==false)
                    break;
               else
                    this.actionsBuffer.splice(i,1);
                ret=null;
            }
    
    
            this.saveAll();
        },
    

    并确定行动。请原谅调试控制台消息

    determineAction: function (action) {
    
            var url="";
            var verb="";
    
            switch(action.action)
            {
                case "ADD_STEP":
                    delete action.data.ActorList;
                    url=this.props.server+"/workflows/"+this.props.workflowid+"/steps";
                    verb="POST";
                    break;
                case "DELETE_STEP":
                    url=this.props.server+"/workflows/"+this.props.workflowid+"/delete/";
                    verb="POST";
                    break;
            }
    
            console.log("Going to call url:",url," with varb:",verb," and data:",action.data);
            $.ajax({
                type: verb,
                url: url,
                data: JSON.stringify(action.data),
                processData:false,
                contentType: 'application/json'
            })
                .success(function(data) {
                    return true;
                    //self.props.onclose(self.state.workflows.WorkflowId);
                })
                .error(function(jqXhr) {
                    console.log(jqXhr);
                    return false;
                });
        },
    

2 个答案:

答案 0 :(得分:0)

您不是在等determineAction完成。让它返回一个承诺,并在你调用它的地方等待它。你的循环也必须是异步的。我创造的尝试可能并不完全符合您的需要,但会向您显示您应该移动的方向。

onAccept: function (e) {
    e.preventDefault();
    var self = this;


    var ret=null;
    // First we do actions in actionsBuffer
    var i = 0;
    function makeRequest() {
        self.determineAction(self.actionsBuffer[i]).success(function() {
            i++;
            if (i >= (self.actionsBuffer.length) {
                 self.saveAll();
            } else {
                makeRequest();
            }

        }).error(function(){
            self.saveAll();
        })
    }
    makeRequest()

    this.saveAll();
},


determineAction: function (action) {

    var url="";
    var verb="";

    switch(action.action)
    {
        case "ADD_STEP":
            delete action.data.ActorList;
            url=this.props.server+"/workflows/"+this.props.workflowid+"/steps";
            verb="POST";
            break;
        case "DELETE_STEP":
            url=this.props.server+"/workflows/"+this.props.workflowid+"/delete/";
            verb="POST";
            break;
    }

    console.log("Going to call url:",url," with varb:",verb," and data:",action.data);
    return $.ajax({
        type: verb,
        url: url,
        data: JSON.stringify(action.data),
        processData:false,
        contentType: 'application/json'
    });
},

答案 1 :(得分:0)

而不是与for循环同步迭代您的操作数组。相反,将其视为一个队列。

  1. 从队列中取出第一项并执行它。
  2. 当异步工作完成时,从中获取另一个项目 队列中。
  3. 重复直到您清除队列。
  4. 这是一个简单的例子。

    function processActions(actionQueue) {
      if(actionQueue.length == 0) return;
    
      // take the first action from the queue
      var action = actionQueue[0];
    
      // assuming determineAction() returns a promise
      determineAction(action)
        .then(function() {
          var remainingActions = actionQueue.slice(1);
    
          // we know this action has completed, so we can pass
          // the remaining actions to be processed
          processActions(remainingActions);
        });
    }