如何同步JavaScript回调? [英] How to sync JavaScript callbacks?

查看:78
本文介绍了如何同步JavaScript回调?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经用JavaScript进行开发了一段时间,但仍然是一名牛仔开发人员,因为一直困扰着我的众多事情之一就是同步JavaScript的回调.

I've been developing in JavaScript for quite some time but net yet a cowboy developer, as one of the many things that always haunts me is synching JavaScript's callbacks.

我将描述引发这种担忧时的一般情况:我有一堆操作要通过for循环执行多次,并且每个操作都有一个回调.在for循环之后,我需要执行其他操作,但是只有完成了for循环的所有回调后,此操作才能成功执行.

I will describe a generic scenario when this concern will be raised: I have a bunch of operations to perform multiple times by a for loop, and each of the operations has a callback. After the for loop, I need to perform another operation but this operation can only execute successfully if all the callbacks from the for loop are done.

代码示例:

 for ... in ... {
   myFunc1(callback); // callbacks are executed asynchly
 }

 myFunc2(); // can only execute properly if all the myFunc1 callbacks are done

建议的解决方案:

在循环的开始处启动一个计数器,以保持循环的长度,并且每个回调都会使该计数器递减.当计数器达到0时,执行myFunc2.从本质上讲,这是为了让回调知道它是否是序列中的最后一个回调,如果是,请在完成后调用myFunc2.

Initiate a counter at the beginning of the loop holding the length of the loop, and each callback decrements that counter. When the counter hits 0, execute myFunc2. This is essentially to let the callbacks know if it's the last callback in sequence and if it is, call myFunc2 when it's done.

问题:

  1. 您的代码中的每个此类序列都需要一个计数器,并且到处都没有意义的计数器不是一个好习惯.
  2. 如果您还记得经典同步问题中的线程冲突方式,那么当多个线程都在同一个var上调用var--时,将会发生不良结果.在JavaScript中会发生同样的事情吗?

最终问题:

有更好的解决方案吗?

推荐答案

好消息是JavaScript是单线程的.这意味着解决方案通常可以与共享"变量配合使用,即不需要互斥锁.

The good news is that JavaScript is single threaded; this means that solutions will generally work well with "shared" variables, i.e. no mutex locks are required.

如果要序列化异步任务,然后执行完成回调,则可以使用以下帮助器功能:

If you want to serialize asynch tasks, followed by a completion callback you could use this helper function:

function serializeTasks(arr, fn, done)
{
    var current = 0;

    fn(function iterate() {
        if (++current < arr.length) {
            fn(iterate, arr[current]);
        } else {
            done();
        }
    }, arr[current]);
}

第一个参数是每次通过都需要传递的值的数组,第二个参数是循环回调(如下所述),最后一个参数是完成回调函数.

The first argument is the array of values that needs to be passed in each pass, the second argument is a loop callback (explained below) and the last argument is the completion callback function.

这是循环回调函数:

function loopFn(nextTask, value) {
    myFunc1(value, nextTask);
}

传递的第一个参数是一个将执行下一个任务的函数,它应传递给您的asynch函数.第二个参数是值数组的当前条目.

The first argument that's passed is a function that will execute the next task, it's meant to be passed to your asynch function. The second argument is the current entry of your array of values.

让我们假设该任务是这样的:

Let's assume the asynch task looks like this:

function myFunc1(value, callback)
{
  console.log(value);
  callback();
}

它打印出值,然后调用回调函数;简单.

It prints the value and afterwards it invokes the callback; simple.

然后,使整个过程动起来:

Then, to set the whole thing in motion:

serializeTasks([1,2, 3], loopFn, function() {
    console.log('done');
});

演示

要并行化它们,您需要一个不同的函数:

To parallelize them, you need a different function:

function parallelizeTasks(arr, fn, done)
{
    var total = arr.length,
    doneTask = function() {
      if (--total === 0) {
        done();
      }
    };

    arr.forEach(function(value) {
      fn(doneTask, value);
    });
}

您的循环函数将是这个(仅更改参数名称):

And your loop function will be this (only parameter name changes):

function loopFn(doneTask, value) {
    myFunc1(value, doneTask);
}

演示

这篇关于如何同步JavaScript回调?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆