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


Answers:


348

处理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. 每个处理程序(成功或错误)都可以返回一个value,它将作为argument链中promise的传递给下一个函数。
  6. 如果一个处理程序返回一个promise(发出另一个异步请求),则仅在该请求完成后才调用下一个处理程序(成功或错误)。

因此,前面的示例代码可能会使用promise和$httpservice(在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


3
写得很好。这确实帮助我实现了承诺。
Ju66ernaut 2016年

错误处理程序(第二个参数)是否始终是可选的?
1.21吉瓦

到目前为止,这是我迄今为止看到的最好的答案!
伊玛目·布克斯

78

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

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

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

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


4
就像执行任务完成时执行的回调一样吗?它有什么不同
穆罕默德·乌默尔

3
JavaScript的公司承诺在其他评论说:A promise can only succeed or fail onceIf a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called

此外,Promise掘金解释了如何使用promise以及如何使用callback
Xiao

在第一页上,缺少很多代码(大的白色空白)。大多数人会想到检查元素,并在下面找到小提琴的URL。此消息适用于其余小提琴–仍然有效;)
DanteTheSmith

1
@MuhammadUmer:阅读此stackoverflow.com/a/31453579/1350476(Sid回答)
SharpCoder

32

据我所知,(在撰写本文时)没有内置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上关联的函数关联为成功或失败。


12
那时还没有内置的功能.then,但是ES6中现在有了
janfoeh 2013年

感谢您的答复,我期待一些很酷的promise回调,但事实证明这是一个实际的名为'then'的函数,该函数已返回。
spartikus's

15

这是我为自己做的事情,目的是弄清楚事情是如何工作的。我想其他人也可以找到这个具体的例子有用:

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>


5

这是一个小JS_Fiddle。

然后是一个方法回调堆栈,在解决了约定后就可以使用它,它是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}`)
})

定义:: 然后是用于解决异步回调的方法

这是ES6中引入的

请在此处找到适当的文档Es6承诺


您的答案实际上并未回答问题。它仅提供API使用情况的示例,而没有说明其then来源和工作方式。您应该改善答案以提供这些详细信息。
Didier L

@TarandeepSingh-首先,然后在其中声明电池状态的语句中,不会返回任何承诺对象。那么,第二秒钟的用途是什么
Mohit Jain

@MohitJain它展示了即使没有任何新的承诺,您也可以执行多个回调。因为,多次调用也可以通过Promise.all完成。
塔兰迪普·辛格

您是指“ 方法回调堆栈 ”吗?
Bergi

4

我怀疑doSome返回此值,即myObj,它也具有then方法。标准方法链接...

如果doSome作为执行doSome的对象没有返回此值,请放心它会使用then方法返回某个对象...

正如@patrick指出的,标准js没有then()


1
我怀疑doSome返回本 -没有强制实施/证明这种suspitions
撒拉杰尼斯

1

doSome(“ task”)必须返回一个Promise对象,并且该Promise始终具有then函数。因此您的代码就是这样

promise.then(function(env) {
    // logic
}); 

而且您知道这只是对成员函数的普通调用。


1

.then 在异步函数中返回一个Promise。

一个很好的例子是:

var doSome = new Promise(function(resolve, reject){
    resolve('I am doing something');
});

doSome.then(function(value){
    console.log(value);
});

要向其添加其他逻辑,您还可以添加reject('I am the rejected param')调用函数并console.log它。


0

在这种情况下,then()是method返回的对象的类doSome()方法。



-1

另一个例子:

new Promise(function(ok) {
   ok( 
      /* myFunc1(param1, param2, ..) */
   )
}).then(function(){
     /* myFunc1 succeed */
     /* Launch something else */
     /* console.log(whateverparam1) */
     /* myFunc2(whateverparam1, otherparam, ..) */
}).then(function(){
     /* myFunc2 succeed */
     /* Launch something else */
     /* myFunc3(whatever38, ..) */
})

使用箭头函数速记的相同逻辑:

new Promise((ok) =>
   ok( 
      /* myFunc1(param1, param2, ..) */
)).then(() =>
     /* myFunc1 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc2(whateverparam1, otherparam, ..) */
).then(() =>
     /* myFunc2 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc3(whatever38, ..) */
)


-4

我迟到了8年,好吧……无论如何,我真的不知道then()会做什么,但也许MDN可能有答案。实际上,我可能实际上对它有所了解。

这将显示您所需的所有信息(希望如此)。除非有人已经发布了此链接。 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

格式为promise.prototype.then()promise和prototype有点像变量,但与javascript中的变量不同,我的意思是像其他东西一样,例如navigator.getBattery()。then()实际存在但它存在的地方几乎没有在网络上使用过,如果您有兴趣,它可以显示有关设备电池的状态,更多信息以及有关MDN的更多信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.