【问题标题】:Synchronous tasks with asynchronous task同步任务与异步任务
【发布时间】:2016-12-20 07:07:29
【问题描述】:

我正在将一个验证组件放在一个应用程序上,该组件接受一个任务名称(可能是一个字段名称)和一个值作为它的参数。对于每个找到的 form 字段,都会启动一个任务。

如果验证失败则返回错误,否则输入正常并启动下一个字段任务,直到处理完所有字段。

在下面的示例中,task_1 按预期工作。但是,在可能需要 HTTP 请求的情况下(由 setTimeout 模拟),task_2 不会返回所需的结果。

我确信这与异步性有关,也许有更好的方法来实现这种机制。这实际上将在 NodeJS 后端实现,其中async 库可用,我会接受使用异步的解决方案。

请参阅Fiddle 了解以下示例。或者这个 Fiddle 用于异步实现。

/**
 * Selecting task_1 below, will have the desired results,
 * however if you run task_2 the final task will not work?
 * A setTimeout() has been used to simulate a HTTP request etc..
 */

// output element
var $output = $$('output')

// configuration object, each task has an 
// array of functions which must accept a
// value which would be validated
var jobs = {
  task_1: [
    function(val, cb) {
      cb(null, val)
    },
    function(val, cb) {
      cb('Error', null)
    }
  ],
  task_2: [
    function(val, cb) {
      cb(null, val)
    },
    function(val, cb) {
      setTimeout(function() {
        cb('An ajax request has an error', null)
      }, 2000)
    }
  ]
}

// run a task and pass a value
taskRunner('task_2', 'Karl')

// taskRunner
function taskRunner(job, val) {
  var tasks = jobs[job]
  var errors = []

  if (tasks) {
    // run the found tasks
    for (i = 0; i < jobs[job].length; i++) {
      tasks[i](val, function(err, result) {
        if (err) {
          errors.push(err)
        }
      })
    }

    // generate the html output
    var html = errors.length > 0 ? [
      '<strong class="text-danger">',
      'Failure</strong>',
      '<pre>',
      errors,
      '</pre>'
    ].join('') : [
      '<strong class="text-success">',
      'Success</strong>',
      '<pre>All validations passed</pre>'
    ].join('')
    $output.html(html).fadeIn()
  } else {
    // return an error message if no tasks have been found
    $output.html('<span class="text-danger">There are no tasks for ' + job + '.</span>').fadeIn()
  }
}

// select elements by data attribute
function $$(val) {
  return $('[data-' + val + ']')
}
/* default */
html,
body {
  margin: 0;
  padding: 0;
  font-family: "Lucida Console", Monaco, monospace !important;
  background: whitesmoke;
  color: #333;
}


/* output container */
.output {
  max-width: 75%;
  margin: 5% auto;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 3px;
  background: white;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}


/* formatted output */
pre {
  background: #FAFAFA;
  padding: 15px;
  margin-bottom: 0;
}


/* type styles */
.text-muted {
  opacity: .5
}

.text-danger {
  color: #D00
}

.text-success {
  color: #0D0
}


/* hide if empty */
.js-hide {
  display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="output js-hide" data-output></div>

【问题讨论】:

    标签: javascript node.js asynchronous async.js


    【解决方案1】:

    你应该在所有回调完成后生成 html 输出

    为了这个目的,你可以使用promise.all

    但对于回调,您可以使用此代码

    var doneCallback=0;
    for (i = 0; i < jobs[job].length; i++) {
      tasks[i](val, function(err, result) {
        if (err) {
          errors.push(err)
        }
        doneCallback++;
        if(doneCallback==jobs[job].length)generateHtml();
      })
    }
    
    // generate the html output
    function generateHtml(){
      var html = errors.length > 0 ? [
         '<strong class="text-danger">',
         'Failure</strong>',
         '<pre>',
         errors,
         '</pre>'
       ].join('') : [
         '<strong class="text-success">',
         'Success</strong>',
         '<pre>All validations passed</pre>'
       ].join('')
       $output.html(html).fadeIn();
    }
    

    /**
     * Selecting task_1 below, will have the desired results,
     * however if you run task_2 the final task will not work?
     * A setTimeout() has been used to simulate a HTTP request etc..
     */
    
    // output element
    var $output = $$('output')
    
    // configuration object, each task has an 
    // array of functions which must accept a
    // value which would be validated
    var jobs = {
      task_1: [
        function(val, cb) {
          cb(null, val)
        },
        function(val, cb) {
          cb('Error', null)
        }
      ],
      task_2: [
        function(val, cb) {
          cb(null, val)
        },
        function(val, cb) {
          setTimeout(function() {
            cb('An ajax request has an error', null)
          }, 2000)
        }
      ]
    }
    
    // run a task and pass a value
    taskRunner('task_2', 'Karl')
    
    // taskRunner
    function taskRunner(job, val) {
      var tasks = jobs[job]
      var errors = []
    
      if (tasks) {
        // run the found tasks
        var doneCallback=0;
        for (i = 0; i < jobs[job].length; i++) {
           tasks[i](val, function(err, result) {
              if (err) {
                errors.push(err)
              }
              doneCallback++;
              if(doneCallback==jobs[job].length)generateHtml();
           })
        }
    
        // generate the html output
        function generateHtml(){
           var html = errors.length > 0 ? [
             '<strong class="text-danger">',
             'Failure</strong>',
             '<pre>',
              errors,
             '</pre>'
            ].join('') : [
              '<strong class="text-success">',
              'Success</strong>',
              '<pre>All validations passed</pre>'
            ].join('')
           $output.html(html).fadeIn();
         }
      } else {
        // return an error message if no tasks have been found
        $output.html('<span class="text-danger">There are no tasks for ' + job + '.</span>').fadeIn()
      }
    }
    
    // select elements by data attribute
    function $$(val) {
      return $('[data-' + val + ']')
    }
    /* default */
    html,
    body {
      margin: 0;
      padding: 0;
      font-family: "Lucida Console", Monaco, monospace !important;
      background: whitesmoke;
      color: #333;
    }
    
    
    /* output container */
    .output {
      max-width: 75%;
      margin: 5% auto;
      padding: 15px;
      border: 1px solid #ddd;
      border-radius: 3px;
      background: white;
      box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
    }
    
    
    /* formatted output */
    pre {
      background: #FAFAFA;
      padding: 15px;
      margin-bottom: 0;
    }
    
    
    /* type styles */
    .text-muted {
      opacity: .5
    }
    
    .text-danger {
      color: #D00
    }
    
    .text-success {
      color: #0D0
    }
    
    
    /* hide if empty */
    .js-hide {
      display: none
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="output js-hide" data-output></div>

    【讨论】:

    • 感谢您的回答。我现在将它放在一个循环中以遍历表单元素,但 setTimeout() 没有按预期返回。如果我提供小提琴,你能帮忙吗?
    • 您能否提供一个promise.all 实现的示例?
    【解决方案2】:
    the best way to complete your requirement using async .
    var async = require('async');
    var name = ["shekhar", 'vishal', "param", "abhishek", 'amit'];
        for (var i = 0; i < 5; i++) {
            var task_1 = name[i];//execute your first loop here
        }
        async.eachSeries(task_1, task_2, function (err) {
            if (err) {
                res.json({status: 0, msg: "OOPS! How is this possible?"});
            }
            res.json("Series Processing Done");
        })
        function task_2(item, callback) {
    //execute your second loop here
            });
    

    【讨论】:

    • 谢谢,我已经使用异步实现了上述功能。请参阅jsfiddle.net/e9jdje72/1。我有同样的问题,异步 HTTP 请求 (setTimeout()) 没有返回它的错误。
    猜你喜欢
    • 2018-07-01
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 2017-12-06
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多