JavaScript promise是一个对象,表示异步任务完成或者失败及其结果值。javascript
完结。java
我固然是开玩笑的。那么,这个定义到底意味着什么?git
首先,JavaScript
中的许多东西都是对象。你能够经过几种不一样的方式进行建立对象。最经常使用的方法是使用对象字面量语法:github
const myCar = {
color: 'blue',
type: 'sedan',
doors: '4',
};
复制代码
你还能够建立一个类
,并经过new
关键字对其进行实例化。数据库
class Car {
constructor(color, type, doors) {
this.color = color;
this.type = type;
this.doors = doors
}
}
const myCar = new Car('blue', 'sedan', '4');
复制代码
console.log(myCar);
复制代码
promise
只是咱们建立的对象,就像后面的例子同样,咱们使用new
关键字对其进行实例化。咱们传入一个带有两个参数的函数,其参数为resolve
和reject
,而不是像传递给咱们Car
的三个参数(颜色,类型和门)。promise
最终,promise
告诉咱们一些关于咱们从它返回的异步函数的完成状况--生效了或失败了。咱们认为这个功能是成功的,若是promise
是解决了,而且说promise
被拒绝是不成功的。服务器
const myPromise = new Promise(function(resolve, reject) {});
复制代码
console.log(myPromise);
复制代码
留意,此时的promise是pending状态网络
const myPromise = new Promise(function(resolve, reject) {
resolve(10);
});
复制代码
留意,咱们用10返回解决了promiseapp
看,不是太可怕 -- 只是咱们建立的对象。并且,若是咱们稍微展开一下:dom
留意,咱们有一些咱们能够访问的方法,即"then"和"catch"
此外,咱们能够传咱们喜欢的东西到resolve
和reject
中。例如,咱们能够传递一个对象,而不是一个字符串:
return new Promise((resolve, reject) => {
if(somethingSuccesfulHappened) {
const successObject = {
msg: 'Success',
data,//...some data we got back
}
resolve(successObject);
} else {
const errorObject = {
msg: 'An error occured',
error, //...some error we got back
}
reject(errorObject);
}
});
复制代码
或者,为了方便查看,咱们任何东西都不传:
return new Promise((resolve, reject) => {
if(somethingSuccesfulHappend) {
resolve()
} else {
reject();
}
});
复制代码
JavaScript
是单线程的。这意味着它一次只能处理一件事。想象这么条道路,你能够将JavaScript
视为单车道的高速公路。特定代码(异步代码)能够滑动到一边,以容许其余代码越过它。完成异步代码后,它将返回到道路。
旁注,咱们能够从任何函数返回
promise
。他没必要是异步的。话虽这么说,promise
一般在它们返回的函数是异步的状况下返回。例如,具备将数据保存在服务器的方法API将是返回promise
的绝佳候选者!
外号:
promise
为咱们提供了一种等待异步代码完成,从中捕获一些值,并将这些值传递给程序其余部分的方法。
我这里有篇文章深刻探讨这些概念:Thrown For a Loop: Understanding Loops and Timeouts in JavaScript。
使用promise
也称为消费promise
。在上面的示例中,咱们的函数返回了一个promise
对象。这容许咱们使用方法的链式功能。
我打赌你看到过下面的这种链式方法:
const a = 'Some awesome string';
const b = a.toUpperCase().replace('ST', '').toLowerCase();
console.log(b); // some awesome ring
复制代码
如今,(伪装)回想下咱们的promise
:
const somethingWasSuccesful = true;
function someAsynFunction() {
return new Promise((resolve, reject){
if (somethingWasSuccesful) {
resolve();
} else {
reject()
}
});
}
复制代码
而后,经过链式方法调用咱们的promise
:
someAsyncFunction
.then(runAFunctionIfItResolved(withTheResolvedValue))
.catch(orARunAfunctionIfItRejected(withTheRejectedValue));
复制代码
想象一下,你有一个从数据库中获取用户的功能。我在codepen上编写了一个示例函数,用于模拟你可能使用的API。它提供了两种访问结果的选项。一,你能够提供回调功能,在其中访问用户或提示错误。或者第二种,函数返回一个promise
做为用户访问或提示错误的方法。
为了方便查看,我把做者的codepen上的代码复制了下来,以下:
const users = [
{
id: '123',
name: 'John Smith',
posts: [
{title: 'Some amazing title', content: 'Here is some amazing content'},
{title: 'My favorite title', content: 'My favorite content'},
{title: 'A not-so-good title', content: 'The not-so-good content'},
]
},
{
id: '456',
name: 'Mary Michaels',
posts: [
{title: 'Some amazing title', content: 'Here is some amazing content'},
{title: 'My favorite title', content: 'My favorite content'},
{title: 'A not-so-good title', content: 'The not-so-good content'},
]
},
]
function getUserPosts(id, cb) {
const user = users.find(el => el.id === id);
if (cb) {
if (user) {
return cb(null, user);
}
return cb('User Not Found', null);
}
return new Promise(function(resolve, reject){
if (user) {
resolve(user);
} else {
reject('User not found');
}
});
}
/* The above code is collapsed to simulate an API you might use to get user posts for a * particular user from a database. * The API can take a callback as a second argument: getUserPosts(<id>, <callback>); * The callback function first argument is any error and second argument is the user. * For example: getUserPosts('123', function(err, user) { if (err) { console.log(err) } else { console.log(user); } }); * getUserPosts also returns a promise, for example: getUserPosts.then().catch(); * The ID's that will generate a user are the of type string and they are '123' and '456'. * All other IDs will return an error. */
getUserPosts('123', function(err, user) {
if (err) {
console.log(err);
} else {
console.log(user);
}
});
getUserPosts('129', function(err, user) {
if (err) {
console.log(err);
} else {
console.log(user);
}
});
getUserPosts('456')
.then(user => console.log(user))
.catch(err => console.log(err));
复制代码
传统上,咱们将经过使用回调来访问异步代码的结果。
rr someDatabaseThing(maybeAnID, function(err, result)) {
//...Once we get back the thing from the database...
if(err) {
doSomethingWithTheError(error)
} else {
doSomethingWithResults(results);
}
}
复制代码
在它们变得过分嵌套以前,回调的使用是能够的。换句话说,你必须为每一个新结果运行更多异步代码。回调的这种模式可能会致使“回调地狱”。
Promise
为咱们提供了一种更优雅,更易读的方式来查看咱们程序流程。
doSomething()
.then(doSomethingElse) // and if you wouldn't mind
.catch(anyErrorsPlease);
复制代码
想象一下,你找到了一碗汤。在你喝以前,你想知道汤的温度。可是你没有温度计,幸运的是,你可使用超级计算机来告诉你汤的温度。不幸的是,这台超级计算机最多可能须要10秒才能得到结果。
这里须要有几点须要注意:
result
的全局变量。Math.random()
和setTimeout()
模拟网络延迟的持续时间。Manth.random()
模拟温度。运行函数并打印结果。
getTemperature();
console.log(results); // undefined
复制代码
该功能须要必定的时间才能运行。在延迟结束以前,不会设置变量。所以,当咱们运行该函数时,setTimeout
是异步的。setTimeout
中的部分代码移出主线程进入等待区域。
我这里有篇文章深刻研究了这个过程:Thrown For a Loop: Understanding Loops and Timeouts in JavaScript
因为设置变量result
的函数部分移动到了等待区域直到完成,所以咱们的解析器能够自由移动到下一行。在咱们的例子中,它是咱们的console.log()
。此时,因为咱们的setTimeout
未结束,result
仍未定义。
那咱们还能尝试什么呢?咱们能够运行getTemperature()
,而后等待11秒(由于咱们的最大延迟是10秒),而后打印出结果。
getTemperature();
setTimeout(() => {
console.log(result);
}, 11000);
// Too Hot | Delay: 3323 | Temperature: 209 deg
复制代码
这是可行的,但这种技术问题是,尽管在咱们的例子中,咱们知道了最大的网络延迟,但在实际中它可能偶尔须要超过10秒。并且,即便咱们能够保证最大延迟10秒,若是result
出结果了,咱们也是在浪费时间。
咱们将重构getTemperature()
函数以返回promise。而不是设置结果。咱们将拒绝promise,除非结果是“恰到好处”,在这种状况下咱们将解决promise
。在任何一种状况下,咱们都会传递一些值到resolve
和reject
。
如今,咱们可使用正在返回的promise结果(也称为消费promise)。
getTemperature()
.then(result => console.log(result))
.catch(error => console.log(error));
// Reject: Too Cold | Delay: 7880 | Temperature: 43 deg
复制代码
.then
,当咱们的promise解决时,它将被调用,并返回咱们传递给resolve
的任何信息。
.catch
,当咱们的promise拒绝时,它将被调用,并返回咱们传递给reject
的任何信息。
最有可能的是,你将更多的使用promise,而不是建立它们。在任何状况下,它们有助于使咱们的代码更优雅,可读和高效。
return new Promise((resolve, reject)=> {})
返回一个promise。.then
从已经解决的promise中获取信息,而后使用.catch
从拒绝的promise中获取信息。