异步函数和对象参数并发



所以今天我遇到了这个花了我很长时间才弄清楚的错误:

async function embed (url, embedOptions={}) => {
embedOptions.url = url;
console.log("Before:");
console.log(url)
console.log(embedOptions.url)
const accessToken = await getAccessToken()
const requestOptions = {
hostname: 'api.twitter.com',
port: 443,
method: 'GET',
path: '/1.1/statuses/oembed.json?' + qs.stringify(embedOptions),
headers: {
'Authorization': 'Bearer ' + accessToken,
},
}
console.log("After")
console.log(url)
console.log(embedOptions.url)
return new Promise((resolve, reject) =>
https.request(requestOptions, res => {
let data = ''
res.on('data', chunk => data += chunk)
res.on('end', () => resolve(JSON.parse(data)))
}).end()
)
}

该函数在三个不同的url上被调用,生成输出:

Before:
https://twitter.com/326665662/statuses/1233300061154664453
https://twitter.com/326665662/statuses/1233300061154664453
Before:
https://twitter.com/36262503/statuses/1233462038854283264
https://twitter.com/36262503/statuses/1233462038854283264
Before:
https://twitter.com/929823128259387392/statuses/1233431896081629184
https://twitter.com/929823128259387392/statuses/1233431896081629184
After
https://twitter.com/326665662/statuses/1233300061154664453
https://twitter.com/929823128259387392/statuses/1233431896081629184
After
https://twitter.com/36262503/statuses/1233462038854283264
https://twitter.com/929823128259387392/statuses/1233431896081629184
After
https://twitter.com/929823128259387392/statuses/1233431896081629184
https://twitter.com/929823128259387392/statuses/1233431896081629184

我很确定我基本上已经弄清楚了为什么const accessToken = await getAccessToken()被调用时会发生这种情况——函数暂停,但embed函数的下一次调用发生了,并在对embedOptions对象的引用中覆盖了embedOptions.url,因为所有函数调用都会更改对同一对象的引用的所有calss。这是正确的吗?若这是保护自己在未来不会犯同样错误的最好方法吗?

你说得对。传递给函数的任何对象都将通过引用传递,并在设置url道具时进行修改。

防止这些错误的最简单方法是小心不要修改对象。另一种选择是使用embedOptions:中的值创建新对象

const embedCopy = Object.assign({}, embedOptions);
embedCopy.url = url;

如果您的对象不包含作为值的对象,这将起作用,在这种情况下,您需要对对象进行深入复制。

有很多库可以处理这个问题,比如lodashramda