简单地返回promise的函数和使用
async
声明的函数之间有一个很小但非常重要的区别。
看一下以下代码片段:
function fn(obj) { const someProp = obj.someProp return Promise.resolve(someProp) } async function asyncFn(obj) { const someProp = obj.someProp return Promise.resolve(someProp) } asyncFn().catch(err => console.error('Catched'))
如您所见,这两个函数具有相同的主体,我们试图在其中访问两种情况下都未定义的参数的属性。 这两个函数之间的唯一区别
asyncFn
使用
async
声明了
asyncFn
。
这意味着JavaScript可以确保
asnycFn
函数返回一个promise(成功或失败),即使其中发生错误,在我们的例子中,
.catch()
块也可以捕获它。
但是,对于
fn
函数,引擎尚不知道该函数将返回
.catch()
,因此代码将不会到达
.catch()
块,该错误将不会被捕获并落入控制台。
更多生活例子
我知道您现在在想什么:
“什么时候我会犯这样的错误?”
猜到了吗
好吧,让我们创建一个执行此操作的简单应用程序。
假设我们有一个使用Express和MongoDB构建的应用程序,该应用程序使用MongoDB Node.JS驱动程序。 如果您不信任我,我会将所有源代码都放在
此Github存储库中 ,以便您可以克隆它并在本地运行它,但是我还将在此处复制所有代码。
这是我们的
app.js
文件:
仔细看看
.catch()
块! 这就是魔法将(不会)发生的地方。
db.js
文件用于连接到mongo数据库:
'use strict' const MongoClient = require('mongodb').MongoClient const url = 'mongodb://localhost:27017' const dbName = 'async-promise-test' const client = new MongoClient(url) let db module.exports = { connect() { return new Promise((resolve, reject) => { client.connect(err => { if (err) return reject(err) console.log('Connected successfully to server') db = client.db(dbName) resolve(db) }) }) }, getDb() { return db } }
最后,我们有一个
user-model.js
文件,其中当前仅定义了一个
getUserById
函数:
如果
app.js
查看
app.js
文件,您将看到当我们进入
localhost:3000/users/<id>
我们将调用
user-model.js
定义的
getUserById
函数,并将
id
参数作为请求传递。
假设您转到以下地址:
localhost:3000/users/1
。 您认为接下来会发生什么?
好吧,如果您回答:“我将从MongoClient中看到一个巨大的错误”-您是正确的。 更精确地说,您将看到以下错误:
Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
。
而且您认为
.catch()
块会在下一个代码段中调用吗?
不行 他不会被叫。
如果将函数声明更改为此,会发生什么?
module.exports = {
是的,您开始了解什么。 我们的
.catch()
块将被调用,我们将能够处理捕获的错误并将其显示给用户。
而不是结论
希望这些信息对某些人有所帮助。 请注意,本文并不试图强迫您始终使用异步功能-尽管它们非常酷。 它们有自己的用例,但它们仍然是诺言之上的语法糖。
我只是想让您知道有时许诺会产生很大的变化,并且当您(是,不是“如果”)遇到本文中讨论的错误时,您将知道其发生的可能原因。
PS注 perev。:原始文章为用户Craig P Hicks留下了有用的评论,我(在评论之后)决定在此处引用:我想提请注意一个细节,在我的开发环境中, Promise.resolve({<body>})
主体中发生的错误未被“发现”:
Promise.resolve((()=>{throw "oops"; })()) .catch(e=>console("Catched ",e));
但是在new Promise()
正文new Promise()
原始“正确的Promise”中大约为transl .:)的主体中发生的错误被“捕获”:
(new Promise((resolve,reject)=>{ resolve((()=>{throw "oops"})()) })) .catch(e=>console.log("Catched ",e));
这个语句怎么样:
async function fn() { <body> }
从语义上讲,此选项等效于此:
function fn() { return new Promise((resolve,reject)=>{ resolve({ <body> }) }) }
因此,如果<body>具有new Promise()
( 在原始“ proper Promise”中为大约Transl。:) ,则下面的代码片段将捕获错误:
function fn() { return Promise.resolve({<body}); }
因此,为了使本文开头的示例在两种情况下都能“捕获”错误,有必要在函数中返回的不是Promise.resolve()
,而是new Promise()
: function fn(obj) { return new Promise((resolve, reject) => { const someProp = obj.someProp; resolve(someProp); }); } async function asyncFn(obj) { return new Promise((resolve, reject) => { const someProp = obj.someProp; resolve(someProp); }); } asyncFn().catch(err => console.error("Catched"));