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

IT技术 javascript
2021-02-08 04:14:40

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

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

哪里then()来的呢?

6个回答

在 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. 每个promise对象都有一个then可以接受两个参数的success 函数,一个error处理程序和一个处理程序。
  3. 在异步任务完成后,函数中的成功错误处理程序then只会被调用一次
  4. then函数还将返回一个promise, 以允许链接多个调用。
  5. 每个处理程序(成功或错误)都可以返回 a value,它将作为sargument链中promise,传递给下一个函数
  6. 如果处理程序返回 a promise(发出另一个异步请求),则仅在该请求完成后才会调用下一个处理程序(成功或错误)。

因此,使用 promise 和$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链条时,我们需要记住一些事情。

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

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

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

考虑以下情况:

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

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

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

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

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

现在什么是延迟对象?

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

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

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

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

这是迄今为止我见过的最好的答案!
2021-03-14 04:14:40
写得很好。这帮助我真正确定了Promise。
2021-03-26 04:14:40
错误处理程序(第二个参数)是否总是可选的?
2021-04-02 04:14:40
这是以难以置信的清晰解释。把你知道的都告诉我。
2021-04-02 04:14:40

then() 函数与某些库或框架(如 jQuery 或 AngularJS)中使用的“Javascript Promise”相关。

Promise是一种处理异步操作的模式。Promise 允许您调用名为“then”的方法,该方法可让您指定用作回调的函数。

有关更多信息,请参阅:http : //wildermuth.com/2013/8/3/JavaScript_Promises

对于 Angular Promise:http : //liamkaufman.com/blog/2013/09/09/using-angularjs-promises/

@MuhammadUmer:阅读这个stackoverflow.com/a/31453579/1350476(Sid 的回答)
2021-03-14 04:14:40
所以它就像一个在任务完成时执行的回调?怎么不一样
2021-03-23 04:14:40
另一条评论中JavaScript Promises说:A promise can only succeed or fail once, 和If a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called
2021-03-24 04:14:40
在第一页上,缺少大块代码(大的白色空白)。大多数人会想到检查元素并在下面找到小提琴的 URL。此消息用于其余部分 - 小提琴仍然有效;)
2021-03-29 04:14:40
此外,Promise nuggets解释了如何使用promise以及将如何使用callback
2021-04-06 04:14:40

据我所知,(在撰写本文时)中没有内置then()方法javascript

似乎无论doSome("task")返回的是什么,都有一个名为then.

如果您将 的返回结果记录doSome()到控制台,您应该能够看到返回内容的属性。

console.log( myObj.doSome("task") ); // Expand the returned object in the
                                     //   console to see its properties.

更新(从 ECMAScript6 开始):-

.then()函数已包含在纯 javascript 中。

这里的 Mozilla 文档

then() 方法返回一个 Promise。它需要两个参数:Promise 成功和失败案例的回调函数。

Promise 对象又被定义为

Promise 对象用于延迟和异步计算。Promise 表示尚未完成但预计在未来完成的操作。

也就是说,Promise充当尚未计算但将在将来解析的值的占位符。.then()函数用于关联在 Promise 解决时要在 Promise 上调用的函数 - 无论是成功还是失败。

感谢这个答案,我期待一些很酷的Promise回调,但结果是一个名为“then”的实际函数被返回。
2021-03-16 04:14:40
那时还没有内置的.then,但是现在 ES6 中的原生 promise 出现了:html5rocks.com/en/tutorials/es6/promises
2021-04-11 04:14:40

这是我为自己制作的东西,以弄清楚事情是如何运作的。我想其他人也会发现这个具体的例子很有用:

doit().then(function() { log('Now finally done!') });
log('---- But notice where this ends up!');

// For pedagogical reasons I originally wrote the following doit()-function so that 
// it was clear that it is a promise. That way wasn't really a normal way to do 
// it though, and therefore Slikts edited my answer. I therefore now want to remind 
// you here that the return value of the following function is a promise, because 
// it is an async function (every async function returns a promise). 
async function doit() {
  log('Calling someTimeConsumingThing');
  await someTimeConsumingThing();
  log('Ready with someTimeConsumingThing');
}

function someTimeConsumingThing() {
  return new Promise(function(resolve,reject) {
    setTimeout(resolve, 2000);
  })
}

function log(txt) {
  document.getElementById('msg').innerHTML += txt + '<br>'
}
<div id='msg'></div>

简单、整洁、实用!
2021-03-22 04:14:40

这是一个小的JS_Fiddle。

then是一个方法回调堆栈,在解决Promise后可用它是像 jQuery 这样的库的一部分,但现在它在原生 JavaScript 中可用,下面是它如何工作的详细说明

您可以在原生 JavaScript 中执行 Promise:就像 jQuery 中的 Promise 一样,每个 Promise 都可以堆叠,然后可以使用 Resolve 和 Reject 回调进行调用,这就是您可以链接异步调用的方式。

我从 MSDN Docs 中分叉并编辑了关于电池充电状态的内容。

这样做是尝试找出用户笔记本电脑或设备是否正在为电池充电。然后被调用,你可以在成功后做你的工作。

navigator
    .getBattery()
    .then(function(battery) {
       var charging = battery.charging;
       alert(charging);
    })
    .then(function(){alert("YeoMan : SINGH is King !!");});

另一个 es6 示例

function fetchAsync (url, timeout, onData, onError) {
    …
}
let fetchPromised = (url, timeout) => {
    return new Promise((resolve, reject) => {
        fetchAsync(url, timeout, resolve, reject)
    })
}
Promise.all([
    fetchPromised("http://backend/foo.txt", 500),
    fetchPromised("http://backend/bar.txt", 500),
    fetchPromised("http://backend/baz.txt", 500)
]).then((data) => {
    let [ foo, bar, baz ] = data
    console.log(`success: foo=${foo} bar=${bar} baz=${baz}`)
}, (err) => {
    console.log(`error: ${err}`)
})

定义 :: then 是一种用于解决异步回调的方法

这是在ES6 中引入的

请在此处找到正确的文档Es6 Promises

@MohitJain 它展示了即使您没有任何新的Promise,您也可以进行多次回调。因为,也可以使用 Promise.all 完成多次调用。
2021-03-16 04:14:40
你的回答实际上并没有回答这个问题。它只提供了一个 API 使用示例,而没有解释它的then来源和工作原理。您应该改进答案以提供这些详细信息。
2021-03-17 04:14:40
方法回调堆栈”是什么意思
2021-03-22 04:14:40
@TarandeepSingh - 在第一个 then 语句中,您提醒电池状态没有返回任何Promise对象。那么第二个然后有什么用
2021-03-24 04:14:40