网站首页 > 博客文章 正文
本文同步本人掘金平台的原创翻译:https://juejin.cn/post/6844903846745997326
promise是什么?
JavaScript promise是一个对象,表示异步任务完成或者失败及其结果值。
完结。
我当然是开玩笑的。那么,这个定义到底意味着什么?
首先,JavaScript中的许多东西都是对象。你可以通过几种不同的方式进行创建对象。最常用的方法是使用对象字面量语法:
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被拒绝是不成功的。
const myPromise = new Promise(function(resolve, reject) {});
复制代码
console.log(myPromise);
复制代码
留意,此时的promise是pending状态
const myPromise = new Promise(function(resolve, reject) {
resolve(10);
});
复制代码
留意,我们用10返回解决了promise
看,不是太可怕 -- 只是我们创建的对象。而且,如果我们稍微展开一下:
留意,我们有一些我们可以访问的方法,即"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。在上面的示例中,我们的函数返回了一个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);
复制代码
写下自己的promise:金发姑娘,三只熊和一台超级计算机
想象一下,你找到了一碗汤。在你喝之前,你想知道汤的温度。但是你没有温度计,幸运的是,你可以使用超级计算机来告诉你汤的温度。不幸的是,这台超级计算机最多可能需要10秒才能获得结果。
这里需要有几点需要注意:
- 我们初始化了一个名为result的全局变量。
- 我们使用Math.random()和setTimeout()模拟网络延迟的持续时间。
- 我们使用Manth.random()模拟温度。
- 我们通过添加一些额外的“math“将延迟和温度限制在一定范围内。温度范围是1到300;延迟范围是1000ms到10000ms(1s到10s)。
- 我们打印出延迟时间和温度,以便我们知道这个功能需多长时间以及我们期望在完成时看到的结果。
运行函数并打印结果。
getTemperature();
console.log(results); // undefined
复制代码
温度是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出结果了,我们也是在浪费时间。
promise来拯救
我们将重构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,而不是创建它们。在任何情况下,它们有助于使我们的代码更优雅,可读和高效。
总结
- Promises是对象,其包含了有关某些异步代码的完成以及我们想要传入的任何结果值的信息对象。
- 我们使用return new Promise((resolve, reject)=> {})返回一个promise。
- 使用promise,我们使用.then从已经解决的promise中获取信息,然后使用.catch从拒绝的promise中获取信息。
- 你可能更多地使用(消费)promises,而不是编写它们。
猜你喜欢
- 2024-10-11 JavaScript,ES6,Promise对象,异步编程的一种解决方案,代码
- 2024-10-11 使用 Matter.js 创建物理模拟:牛顿摆
- 2024-10-11 一首歌带你搞懂Promise(歌曲promise)
- 2024-10-11 如何用Vue3和p5.js绘制一个交互式波浪图
- 2024-10-11 IT技术栈:Javascript中Promise的pending、fulfilled和rejected
- 2024-10-11 Node.js中的Promise:回调的替代方案
- 2024-10-11 我终于真正理解 Promise 了!(promise 的理解)
- 2024-10-11 探究JS中Promise函数then的奥秘(js中promise什么意思)
- 2024-10-11 关于js中的promise,与其说是一种语法还不如说是一种思想!
- 2024-10-11 前端-JavaScript异步编程中的Promise
你 发表评论:
欢迎- 最近发表
-
- 给3D Slicer添加Python第三方插件库
- Python自动化——pytest常用插件详解
- Pycharm下安装MicroPython Tools插件(ESP32开发板)
- IntelliJ IDEA 2025.1.3 发布(idea 2020)
- IDEA+Continue插件+DeepSeek:开发者效率飙升的「三体组合」!
- Cursor:提升Python开发效率的必备IDE及插件安装指南
- 日本旅行时想借厕所、买香烟怎么办?便利商店里能解决大问题!
- 11天!日本史上最长黄金周来了!旅游万金句总结!
- 北川景子&DAIGO缘定1.11 召开记者会宣布结婚
- PIKO‘PPAP’ 洗脑歌登上美国告示牌
- 标签列表
-
- ifneq (61)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)