FCC API 项目。我不明白带有承诺的代码流程
Posted
技术标签:
【中文标题】FCC API 项目。我不明白带有承诺的代码流程【英文标题】:FCC api project. I do not understand the flow of the code with promises 【发布时间】:2021-11-21 07:49:48 【问题描述】:我被一些代码卡住了,我不明白为什么。我决心不复制和粘贴,而是要了解我在做什么(以及做错了什么)。 问题是我想在 post 路由中创建新的 Url 对象。它生成对象,但不等待函数 getHighestShort 解决其承诺,并且始终将 shortMax 返回为 1。 如果我控制台登录一些代码行,我可以看到 getHighestShort 函数中 if 语句中的代码在创建和保存 Url 对象后被解析,因此 Url 对象的 short_url 始终为 1。 我真的很感激一些正确方向的提示,因为我认为在新的 Url 之前的 await 会使那行代码阻碍其余的代码。 -42 岁的自学者——所以这篇文章听起来可能有点过分了:)
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser')
const mongoose = require('mongoose')
const Url = require('./schemas/urlModel');
mongoose.connect('mongodb://localhost:27017/urlshortener', useNewUrlParser: true, useUnifiedTopology: true )
.then(() => console.log('connection open'))
.catch((err) => console.log(err))
const app = express();
// Basic Configuration
const port = process.env.PORT || 3000;
app.use(cors());
app.use('/public', express.static(`$process.cwd()/public`));
app.use(bodyParser.urlencoded( extended: false ))
app.get('/', function(req, res)
res.sendFile(process.cwd() + '/views/index.html');
);
// Your first API endpoint
//find input url in db and return the long version
app.get('/api/shorturl/:input', async (req, res) =>
try
const input = req.params
// const shortUrlNr = parseInt(input)
console.log(input)
console.log(Url.findOne( short_url: `$input` ))
const found = await Url.findOne( short_url: `$input` )
res.redirect(`https://$found.full_url`)
catch (err)
console.log(err)
console.log(res.status)
)
app.post('/api/shorturl/new', async (req, res, next) =>
try
const url = await req.body
//check for valid url, if not respond with json object as asked in tests.
if (!validURL(url))
return res.json(error: 'invalid url')
else
//find url in db and get json response with the corresponding object.
//If it is already in the db, than redirect to this website as asked in tests.
const foundUrl = await Url.findOne( full_url: `$url` )
if (foundUrl !== null)
res.redirect(`https://$foundUrl.full_url`)
else
//if the url is not there, we''ll create a new entry with that url.
const newUrl = await new Url( full_url: `$url`, short_url: `$getHighestShort()` )
await newUrl.save()
res.json(newUrl)
catch(err)
console.log('catch error post request')
return next(err)
)
app.listen(port, function()
console.log(`Listening on port $port`);
);
function validURL(str)
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]2,|'+ // domain name
'((\\d1,3\\.)3\\d1,3))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator
return !!pattern.test(str);
function getHighestShort()
let shortMax = 1
//make an array from the collection with short values sorted descending
//and than pick the first one which should be the highest value.
//if the array is empty just return 1 as it is the first one
Url.find().sort(short_url: 1).exec()
.then(res =>
if (res.length !== 0)
shortMax = res[0].short_url + 1
)
.catch(err =>
console.log('catch err server.js function getHighestShort')
console.log(err)
)
return shortMax
型号
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const urlSchema = new Schema(
full_url:
type: String,
required: false
,
short_url: Number
)
const Url = mongoose.model('Url', urlSchema)
module.exports = Url
【问题讨论】:
【参考方案1】:await 运算符等待promise,以便它像您期望的那样工作。
例如在这一行:
const url = await req.body
await
在这里毫无意义,因为req.body
不是一个承诺,而是一个对象。所以它和做的一样:
const url = req.body
现在为什么您的代码不起作用?让我们从了解getHighestShort
开始,它会返回一个承诺吗? (剧透警告它没有)。
所以首先我们需要让它返回一个承诺(然后我们将不得不等待该承诺解决)。
第一步,让getHighestShort
返回一个promise:
function getHighestShort()
let shortMax = 1
//make an array from the collection with short values sorted descending
//and than pick the first one which should be the highest value.
//if the array is empty just return 1 as it is the first one
return new Promise((resolve, reject) =>
Url.find().sort(short_url: 1).exec()
.then(res =>
if (res.length !== 0)
shortMax = res[0].short_url + 1;
resolve(shortMax)
)
.catch(err =>
console.log('catch err server.js function getHighestShort')
console.log(err)
// you decide logic here
resolve(shortMax)
)
)
现在我个人建议你重新编写一下,让它更简洁一些,如下所示:
async function getHighestShort()
let shortMax = 1
try
//make an array from the collection with short values sorted descending
//and than pick the first one which should be the highest value.
//if the array is empty just return 1 as it is the first one
const results = await Url.find().sort(short_url: 1).limit(1).exec()
if (res.length !== 0)
shortMax = res[0].short_url + 1
return shortMax
catch (e)
console.log('catch err server.js function getHighestShort')
console.log(err)
return shortMax
请注意,我添加了limit(1)
,无需在每次调用时读取整个集合。
我想补充一点,您在这里对操作的原子性有一些错误的假设,如果同时处理 2 个请求会发生什么?您将拥有 2 个具有相同 short_url
的网址。
我会把这个问题留给你自己处理。
第 2 步,现在 getHighestShort
返回了一个承诺。我们需要等待它:
const short_url = await getHighestShort();
const newUrl = await new Url( full_url: `$url`, short_url: short_url )
【讨论】:
感谢您花时间解释事情!以上是关于FCC API 项目。我不明白带有承诺的代码流程的主要内容,如果未能解决你的问题,请参考以下文章
获取api,为啥我必须在响应json()上使用then,试图理解承诺[重复]