【问题标题】:How can you use a callback to guarantee sequential execution?如何使用回调来保证顺序执行?
【发布时间】:2020-04-30 20:12:19
【问题描述】:

我正试图将我的头脑围绕着回调,但我不明白回调如何保证一个语句将在之后(就时间而言)另一个语句执行未知的时间。我不关心 promises、await、async 等,我只关心简单的回调,因为我正在努力学习。


例如下面,我的方法将在未知时间事件发生之前执行回调。我可以看到如何使用回调来执行某些事情在(就时间而言)其他东西已经完成执行并返回了一些有意义的东西。

function foo(callback) {
    setTimeout(() => console.log("Do something with unknown time"),
        2000);
    callback();
}

function callback() {
    console.log("Execute callback");
}

foo(callback);

所以我要问的是回调可以用来保证时域中的执行顺序吗?还是他们的唯一目的是响应事件?

【问题讨论】:

  • 这里的回调不是调用callback()的函数,而是对console.log()的内联调用。
  • 是的,你有一个观点,它是 setTimeout 方法的回调方法。但我想知道的是如何使我的回调在 foo 方法中的第一条语句之后运行。我想要代码做的是等待 2 秒,执行 setTimeout 的回调,即控制台日志,然后执行回调到我的 foo 方法
  • 不过,您的函数并不是真正的回调。不管怎样,这里有一个类似的example of using async and await to do this
  • 我需要什么才能使它成为真正的回调。就像我提供给 setTimeout 方法的那个一样。我想要一种情况,我的方法类似于 setTimeout,但不是等待特定时间,而是等待前一条语句的完整执行。

标签: javascript asynchronous callback asynccallback


【解决方案1】:

回调是一种调用函数的方法,该函数作为参数传递给调用函数(在您的示例中为 foo)。回调保证如果在函数内部调用之前没有发生错误,则调用该函数。回调也不是异步的,但它稍后在函数内部执行一些代码的方式让每个人一开始都认为它是异步的。

正如您在上面的示例中添加了setTimeout 函数,setTimeout 是一个异步回调调用函数,它在某个定义的时间后异步调用它的回调(在您的代码中 () => console.log("Do something with unknown time"))(2000) .因此,setTimeout 不会像您预期的那样停止执行 2 秒,而是让我们执行进一步的代码行,而不必担心回调内部会发生什么。因此,callback() 将在触发foo(callback); 的那一刻触发。

You can find more info about callback in here.

【讨论】:

  • 所以回调与执行的时间无关,而只是我猜测的事件。我很困惑,因为有很多材料声称回调用于处理异步事件。我知道 setTimeout 不会阻止执行,这就是我使用它来表达我的观点的原因。我想知道在 promises、await 等之前如何处理 fetch 请求。
  • 是的,就是这样。即使在异步函数调用中,发生的一切都会回调事件,Promise 有它的 resolvereject 回调,可以稍后处理。这些回调有助于在某些事件发生时调用此类成功或失败事件(例如成功执行的resolve 回调和执行失败或错误的reject 回调)。我希望这是有道理的。你可以在这里找到更多信息:medium.com/front-end-weekly/…
【解决方案2】:

你问了两个问题,

  1. 回调执行顺序是否有保证?

  2. 回调是否只响应事件?

回答

  1. 是的。

据我了解,callback 只是在调用另一个要运行的函数(当它被调用时)

保证调用时立即运行。

为了确保在触发回调之前调用某些内容,只需在执行回调之前将要调用的内容放在前面。

例如从您的代码中,通过稍微修改它,回调保证在执行 console.log 后运行。

function foo(callback) {
    setTimeout(() => {
        console.log("Do something with unknown time");
        callback();
    }, 2000);
}

function callback() {
    console.log("Execute callback");
}

foo(callback);

延迟执行的是setTimeout,与回调方法无关。

  1. 当然,callback 可以作为回调来响应事件,就像elem.addEventListener("click", callback);。但不仅如此。

下面将举例说明。

例如

var map = function(arr, callback) {
  var result = [];
  for (var i = 0, len = arr.length; i < len; i++) {
    result.push(callback(arr[i]));
  }
  return result;
};

map([0, 1, 2, 3], function(item) {
  return item * 2;
})

已编辑

此编辑指的是

例如,如果我正在调用数据库,我不知道检索数据需要多长时间。如果我在它到达之前尝试访问它,我会得到一个错误。

调用数据库与异步 http 请求没有任何区别。所以在这里,我将使用 XMLHttpRequest 来演示如何使用回调来确保这一点。但通常,这些是浏览器或 node.js 中已经提供的功能。所以你不需要自己写。当然,为了防止回调地狱,我个人更喜欢使用Promiseasync/await。但这有点跑题了。

让我们看看 XMLHttpRequest 如何使用回调来处理异步任务。

var sendRequest = function(callback) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
       callback(this); 
    }
  };
  xhttp.open("GET", "filename", true);
  xhttp.send();
}

你可以使用回调来处理异步事件。有时你不知道它什么时候会发生。其工作原理的基本思想来自我在答案 1 中所说的示例。

【讨论】:

  • 我明白把回调();在 setTimeout 的主体内部将使其在 console.log() 方法之后执行,但这不是我的主要问题,因为我只是使用 setTmeout 方法来模拟一个需要未知时间的方法。
  • 只是用一个例子编辑答案,请看一下,看看是否解决了你的问题
  • 不,它不能解决我的问题。当我询问执行顺序时,我的意思是执行完成。例如,如果我正在调用数据库,我不知道检索数据需要多长时间。如果我在它到达之前尝试访问它,我会得到一个错误。在这种情况下,有没有办法使用回调?
【解决方案3】:

如果我理解你的意思正确,你可以使用回调作为事件来做某事,例如:onerror, oncomplete...

在这个例子中,我们开始运行todo函数,我们有oncomplete函数,它可以作为回调函数在完成todo函数后做一些事情。

在运行过程中,如果出现错误,会记录到onerror函数中。

function todo(oncomplete, onerror) {
    try {
        console.log("Start...");

        console.log("Do something with unknown time");

        setTimeout(() => oncomplete(),2000);
        
        // you can try to throw error here to test
        // throw new Error("Some error message...");
    } catch (e) {
        onerror(e);
    }
}

function oncomplete() {
    console.log("Done!");
}

function onerror(e) {
    console.error(e.message);
}

todo(oncomplete, onerror);

【讨论】:

  • 这不是我想要的。要查看我的问题,请考虑在上面的示例中,如果 console.log("Do something with unknown time") 花费了未知时间(例如 5 秒)。然后,setTimeout 方法将在 console.log 之前运行。所以输出将是 Start--> Done --> Do something with unknown time(3 sec later)
  • @HarshLimaye 那么,这意味着你已经把它放错了地方?如果您按照我的步骤重试,会发生什么情况?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-26
  • 2016-04-29
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
  • 2013-11-24
  • 2021-03-07
相关资源
最近更新 更多