函数 then() 在 JavaScript 中是什么意思?

新手上路,请多包涵

我一直在看到看起来像这样的代码:

myObj.doSome("task").then(function(env) {
    // logic
});

then() 从何而来?

原文由 Kay Pale 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 670
1 个回答

在 JavaScript 中处理异步调用的传统方法是使用回调。假设我们必须对服务器进行三个调用,一个接一个,以设置我们的应用程序。使用回调,代码可能类似于以下内容(假设使用 xhrGET 函数进行服务器调用):

 // Fetch some server configuration
    xhrGET('/api/server-config', function(config) {
        // Fetch the user information, if he's logged in
        xhrGET('/api/' + config.USER_END_POINT, function(user) {
            // Fetch the items for the user
            xhrGET('/api/' + user.id + '/items', function(items) {
                // Actually display the items here
            });
        });
    });

在此示例中,我们首先获取服务器配置。然后基于此,我们获取有关当前用户的信息,然后最终获取当前用户的项目列表。每个 xhrGET 调用都采用一个回调函数,该函数在服务器响应时执行。

当然,现在我们拥有的嵌套级别越多,代码就越难阅读、调试、维护、升级和基本使用。这通常被称为回调地狱。此外,如果我们需要处理错误,我们可能需要将另一个函数传递给每个 xhrGET 调用,以告诉它在发生错误时需要做什么。如果我们只想拥有一个通用的错误处理程序,那是不可能的。

Promise API 就是为了解决这个嵌套问题和错误处理问题而设计的。

Promise API 提出以下建议:

  1. 每个异步任务都会返回一个 promise 对象。
  2. Each promise object will have a then function that can take two arguments, a success handler and an error handler.
  3. then 函数中的成功 错误处理程序将仅在异步任务完成后调用 _一次_。
  4. then 函数还将返回一个 promise ,以允许链接多个调用。
  5. 每个处理程序(成功或错误)都可以返回 value ,它将作为 argument 传递给下一个函数,在 promise b9b5dadb4f482e7080555-93a29de 链中
  6. 如果处理程序返回 promise (发出另一个异步请求),则只有在该请求完成后才会调用下一个处理程序(成功或错误)。

因此,前面的示例代码可能会转换为类似以下内容,使用 promises 和 $http 服务(在 AngularJs 中):

 $http.get('/api/server-config').then(
    function(configResponse) {
        return $http.get('/api/' + configResponse.data.USER_END_POINT);
    }
).then(
    function(userResponse) {
        return $http.get('/api/' + userResponse.data.id + '/items');
    }
).then(
    function(itemResponse) {
        // Display items here
    },
    function(error) {
        // Common error handling
    }
);

传播成功和错误

链接承诺是一种非常强大的技术,它允许我们完成很多功能,比如让服务调用服务器,对数据进行一些后处理,然后将处理后的数据返回给控制器。但是当我们使用 promise 链时,我们需要记住一些事情。

考虑以下假设的 promise 具有三个承诺的链,P1、P2 和 P3。每个 promise 都有一个成功处理程序和一个错误处理程序,因此 P1 的 S1 和 E1,P2 的 S2 和 E2,P3 的 S3 和 E3:

 xhrCall()
  .then(S1, E1) //P1
  .then(S2, E2) //P2
  .then(S3, E3) //P3

在没有错误的正常流程中,应用程序将流经 S1、S2,最后是 S3。但在现实生活中,事情永远不会那么顺利。 P1可能遇到错误,或者P2可能遇到错误,触发E1或E2。

考虑以下情况:

• 我们从P1 中的服务器收到成功响应,但返回的数据不正确,或者服务器上没有可用数据(认为是空数组)。在这种情况下,对于下一个承诺 P2,它应该触发错误处理程序 E2。

• 我们收到承诺P2 的错误,触发了E2。但是在处理程序内部,我们有来自缓存的数据,确保应用程序可以正常加载。在这种情况下,我们可能希望确保在 E2 之后调用 S3。

因此,每次我们编写成功或错误处理程序时,我们都需要进行调用——给定我们当前的函数,对于承诺链中的下一个处理程序,这个承诺是成功还是失败?

如果我们想为链中的下一个承诺触发成功处理程序,我们可以从成功或错误处理程序返回一个值

另一方面,如果我们想为链中的下一个承诺触发错误处理程序,我们可以使用 deferred 对象并调用其 reject() 方法来做到这一点

现在什么是延迟对象?

jQuery 中的延迟对象表示稍后将完成的工作单元,通常是异步的。工作单元完成后, deferred 对象可以设置为已解决或失败。

一个 deferred 对象包含一个 promise 对象。通过 promise 对象,您可以指定工作单元完成时要发生的事情。您可以通过在 promise 对象上设置回调函数来实现。

Jquery 中的延迟对象: https ://api.jquery.com/jquery.deferred/

AngularJs 中的延迟对象: https ://docs.angularjs.org/api/ng/service/ $q

原文由 Sid 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题