javascript - Javascript Nested For Loop 在返回数组时不更新数组
问题描述
let posts = [];
for(var i = user.posts.length - 1; i >= 0; i--){
posts.push(user.posts[i]);
}
for(var i = 0; i < user.friends.length; i++){
let query = {username:user.friends[i]};
User.findOne(query, function(err, theuser){
if(err) throw err;
if(theuser){
if(theuser.posts.length > 0){
for(var j = theuser.posts.length - 1; j >= 0; j--){
posts.push(theuser.posts[j]);
}
}
}
});
}
return posts;
所以我的问题是,当我调用这个函数时,帖子没有正确返回。当我运行这个时,我想返回一个帖子数组,第一个 for 循环运行良好,但是当我想将一个元素从 var = j 的嵌套 for 循环推送到数组时,它不会更新帖子数组。我认为它可能与异步功能有关,但我不确定如何在我的情况下实现它。
解决方案
你不能从异步函数返回;至少不像你正在做的那样。
let posts = []
// ...
for(var i = 0; i < user.friends.length; i++){
// ...
User.findOne(query, function(err, theuser){
// nothing here happens before `return posts` is called below
})
}
return posts;
这应该可以帮助您回到正确的道路上-
// reverse copy of user posts
const posts =
[ ...user.posts ].reverse()
// "promisified" findOne
const findOne = query =>
User.findOne
( query
, (err, res) =>
err
? Promise.reject(err)
: Promise.resolve(res)
)
Promise
.all(user.friends.map(username => findOne({ username }))
.map(friend => friend.posts.reverse())
.then(friendPosts => posts.concat(friendPosts)
.then
( allPosts =>
// do something with all posts here
)
替代方案是async
/ await
。这里我们也使用util.promisify
代替findOne
手工重写——
const { promisify } =
require('util')
const findOne =
promisify(User.findOne)
// below, `async` functions always return a promise
const allPostsAndFriendsPosts = async (user) =>
{ // write normal synchronous code here
let res =
[ ...user.posts ].reverse()
// inside async functions, we can `await` a promise
const friends =
await Promise.all(user.friends.map(username => findOne({ username }))
// then use the promised value synchronously
for (const f of friends)
res = res.concat(f.posts.reverse())
return res // <-- returns a promise
}
allPostsAndFriendsPosts(user)
.then
( allPosts =>
// do something with all posts
)
async
并且await
是这个时代的双人组合。我只想对他们的综合能力表示赞赏。假设您有一个数据库-
const DB =
{ '/0': { a: 'a', _link: '/1' }
, '/1': { b: 'b', _link: '/2' }
, '/2': { c: 'c', d: 'd', _link: '/3' }
, '/3': { e: 'e' }
, '/4': { f: 'f', _link: '/5' }
, '/5': { g: 'g' }
// ...
}
每个节点都有一个类似/0
,/1
等的路径,并且节点可以使用该_link
属性链接到其他节点。link->link->link 的链没有长度限制。给定一个起始节点,目标是产生整个节点序列——</p>
recursiveGet ('/0') .then (console.log, console.error)
// [ { a: 'a' }, { b: 'b' }, { c: 'c', d: 'd' }, { e: 'e' } ]
recursiveGet ('/4') .then (console.log, console.error)
// [ { f: 'f' }, { g: 'g' } ]
recursiveGet ('/99') .then (console.log, console.error)
// Error: path not found: /99
我们需要某种方式来定义一个循环,某种方式来初始化它,某种方式来执行下一个循环,最后是某种方式来说明循环何时完成。哦,一切都必须是异步的。
这是一项艰巨的任务,但async
可以await
胜任这项任务。在编写泛型函数时,我们尽可能保持泛型以最大化可重用性 -
const asyncUnfold = async (loop, init) =>
// call the user's loop with
loop
// the "next" function
// accepts two arguments
// 1. the item to add to the result
// 2. the next accumulator
( async (x, acc) =>
// the item is prepended to the recursive result
[ x, ...await asyncUnfold (f, acc) ]
// the "done" function
// accepts one argument
// 1. then final item of the result
, async (x) => [ x ]
// initial accumulator
, init
)
给定一个不执行递归查询的get
函数-
const get = async (url = '') =>
fetch (url) .then (res => res .json ())
我们现在可以recursiveGet
使用asyncUnfold
-
const recursiveGet = async (initUrl) =>
// use our new magic wand
asyncUnfold
// our loop
// receives 3 arguments
// 1. the "next" function
// 2. the "done" function
// 3. the accumulator
( async (next, done, { _link, ...res }) =>
// if we have a _link ...
_link
// add res to the output
// the next step is get(_link)
? next (res, await get (_link))
// otherwise there is no _link
// call done with the last result
: done (res)
// initial accumulator
, await get (initUrl)
)
所有这些都无需触摸Promise
, reject
, resolve
, 或then
。我希望这能让您了解可以使用async
and进行的强大表达await
。在下面的浏览器中验证结果 -
const asyncUnfold = async (f, init) =>
f ( async (x, acc) => [ x, ...await asyncUnfold (f, acc) ]
, async (x) => [ x ]
, init
)
const get = async (url = '') =>
fetch (url) .then (res => res .json ())
const recursiveGet = async (initUrl) =>
asyncUnfold
( async (next, done, { _link, ...res }) =>
_link
? next (res, await get (_link))
: done (res)
, await get (initUrl)
)
const DB =
{ '/0': { a: 'a', _link: '/1' }
, '/1': { b: 'b', _link: '/2' }
, '/2': { c: 'c', d: 'd', _link: '/3' }
, '/3': { e: 'e' }
, '/4': { f: 'f', _link: '/5' }
, '/5': { g: 'g' }
}
// fake fetch for demo
const fetch = (url = '') =>
DB[url] === undefined
? Promise .reject (Error(`path not found: ${url}`)) .then (delay)
: Promise .resolve ({ json: () => DB[url] }) .then (delay)
// fake delay for demo
const delay = (x, ms = 250) =>
new Promise (r => setTimeout (r, ms, x))
recursiveGet ('/0') .then (console.log, console.error)
// [ { a: 'a' }, { b: 'b' }, { c: 'c', d: 'd' }, { e: 'e' } ]
推荐阅读
- amazon-web-services - 使用 SSM 参数存储存储不同的第三方 API 密钥/凭据
- postgresql - Postgres:如何使用单个命令更新表中的多个记录
- javascript - 使用Javascript切换切换时如何再次编辑HTML文本?
- javascript - 使用 javascript 在 lu 列表中添加 li 对象
- java - Corda:如何将 AndComposition 与 VaultCustomQueryCriteria 一起使用
- c++ - openCV:使用重载运算符和不使用矩阵乘法时的不同结果
- http-live-streaming - HLS 播放列表通知
- javascript - React:刷新页面时无法访问组件道具
- ssl - 如何使用 LetsEncrypt 证书设置 https?
- php - MySQL - 每行列出同一组的成员