我看到的代码长这样:
myObj.doSome("task").then(function(env) {
// logic
});
< p > then()
从何而来?我看到的代码长这样:
myObj.doSome("task").then(function(env) {
// logic
});
< p > then()
从何而来?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 提出以下建议:
promise
对象。promise
对象都将具有一个 then
函数,它可以接受两个参数,一个成功处理程序和一个错误处理程序。then
函数中的成功或错误处理程序将仅在异步任务完成后调用一次。then
函数还将返回一个 promise
,以允许链接多个调用。value
,这将作为下一个函数的参数,在 promise
链中传递。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
}
);
传播成功与错误
串联 promises 是一项非常强大的技术,它使我们能够实现许多功能,例如使服务进行服务器调用、对数据进行后处理,然后将处理后的数据返回给控制器。但是当我们使用 promise
链时,有一些事情需要记住。
考虑以下假设的 promise
链,其中包含三个 promises,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中,我们收到服务器的成功响应,但返回的数据不正确,或者服务器上没有数据(考虑空数组)。在这种情况下,对于下一个promise P2,它应该触发错误处理程序E2。
• 我们收到P2的错误,触发E2。但在处理程序内部,我们有来自缓存的数据,确保应用程序可以正常加载。在这种情况下,我们可能希望在E2之后调用S3。
因此,每次编写成功或错误处理程序时,我们需要进行一次调用-鉴于我们当前的函数,这个promise是下一个promise链中的成功还是失败?
如果我们想要触发promise链中下一个promise的成功处理程序,我们可以从成功或错误处理程序中返回一个值
另一方面,如果我们想要触发promise链中下一个promise的错误处理程序,我们可以使用deferred对象并调用其reject()方法
那么deferred对象是什么?
JQuery中的deferred对象表示将在以后完成的工作单元,通常是异步地。一旦工作单元完成,deferred对象可以设置为已解决或已失败。
deferred对象包含一个promise对象。通过promise对象,您可以指定在工作单元完成时要发生的事情。你通过在promise对象上设置回调函数来实现这一点。
JQuery中的Deferred对象: https://api.jquery.com/jquery.deferred/
AngularJs中的Deferred对象:https://docs.angularjs.org/api/ng/service/$q
then()函数与“Javascript promises”相关,这些promises用于一些库或框架中,例如jQuery或AngularJS。
Promise是一种处理异步操作的模式。Promise允许您调用一个名为“then”的方法,该方法可让您指定要用作回调的函数。
有关更多信息,请参见:http://wildermuth.com/2013/8/3/JavaScript_Promises
有关Angular Promises的信息,请参见:http://liamkaufman.com/blog/2013/09/09/using-angularjs-promises/
在ECMAScript6中
使用Promises,JavaScript纯粹地包含了.then()
方法。
来自Mozilla文档:
then()
方法返回一个Promise。它接受两个参数:对于Promise成功和失败情况的回调函数。
而Promise对象则被定义为
Promise对象用于延迟和异步计算。Promise代表着一个尚未完成但将来会完成的操作。
也就是说,Promise
充当着一个还未计算的值的占位符,但预计将来会被解析。而.then()
函数用于将函数与Promise关联起来,当它被解析时,它可以作为成功或失败的标志。
在ECMAScript6之前
据我所知,在javascript
中没有内置的then()
方法(在撰写本文时)。
看起来doSome("task")
返回的结果具有名为then
的方法。
如果您将doSome()
的返回结果记录到控制台中,您应该能够看到所返回内容的属性。
console.log( myObj.doSome("task") ); // Expand the returned object in the
// console to see its properties.
.then()
,但原生的 Promise 现在在 ES6 中被引入了:http://www.html5rocks.com/en/tutorials/es6/promises/ - janfoeh这是我自己制作的一个东西,用于梳理事物的工作原理。我想其他人也可以从这个具体的例子中获益:
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>
then是一个回调方法堆栈,当Promise被解析后可以使用。它是类似于jQuery的库的一部分,但现在也适用于原生JavaScript。以下是详细说明它的工作方式。
您可以在原生JavaScript中使用Promise:就像在jQuery中有promises一样,每个promise都可以堆叠,并且可以使用Resolve和Reject回调进行调用,这就是您可以链接异步调用的方式。
我从MSDN文档中的电池充电状态中进行了fork并编辑。
这个程序的作用是尝试查找用户笔记本电脑或设备是否正在充电电池。然后调用此函数,如果成功,则可以执行后续操作。
navigator
.getBattery()
.then(function(battery) {
var charging = battery.charging;
alert(charging);
})
.then(function(){alert("YeoMan : SINGH is King !!");});
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
then
来自哪里以及它是如何工作的。你应该改进你的回答,提供这些细节。 - Didier L{}
的用法:这三个例子都在做同一件事情(什么也不做),但它们都有有效的语法,并且是一个有效的 Promise 链!
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, ..) */
})
console.log("This code has no errors GG!")
使用箭头函数的简写逻辑,不需要使用 {}
new Promise((ok) =>
ok(
/* myFunc1(param1, param2, ..) */
).then(() =>
0 // HEY DID YOU NOTICE! A number that does nothing,
// but otherwise the parsing will fail!
// The code is pretty clean but have a major downside
// As arrow functions without {} can contains only one declaration
// console.log("something") will FAIL here
).then(() =>
"" // HEY DID YOU NOTICE! An empty string that does nothing,
// but otherwise the parsing will fail!
// As arrow functions without {} can contains only one declaration
// We can't add more code here, hence:
// console.log("something")
// Will break the whole promise
// This is likely the error in y(our) code ;)
))
console.log("This code has no errors GG!")
带有 {}
的箭头函数
new Promise( (ok) => {
ok(
/* myFunc1(param1, param2, ..) */
)
}).then( () => {
/* myFunc1 succeed */
/* Launch something else */
}).then( () => {
/* myFunc2 succeed */
/* Launch something else */
/* myFunc3(whatever38, ..) */
console.log("something")
/* More console logs! */
console.log("something else")
})
console.log("This code has no errors GG!")
.then
在异步函数中返回一个 Promise。
一个好的例子如下:
var doSome = new Promise(function(resolve, reject){
resolve('I am doing something');
});
doSome.then(function(value){
console.log(value);
});
reject('我是被拒绝的参数')
调用函数并将其console.log出来。doSome("task")必须返回一个Promise对象,并且该Promise对象始终具有then函数。因此,您的代码应该像这样:
promise.then(function(env) {
// logic
});
你知道这只是一个普通的成员函数调用。
then()
是由doSome()
方法返回的对象的类方法。