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

查看:23
本文介绍了如何同步 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);
}

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

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天全站免登陆