各位 JS 高手你好,问一个关于 for 循环使用$.post 替换全局变量的问题,好像是竞争锁之类的

300 天前
 abccccabc
各位 JS 高手你好,问一个关于 for 循环使用$.post 替换全局变量的问题,好像是竞争锁之类的。
```
var allimg = 获取到的图片数组;
var oldcontent = 原内容;
for(var i=0; i<allimg.length; i++){
$.post('url', 参数, function(ret) {
if(ret['code'] == 200) {
oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl']);
}else{
console.log(错误信息);
}
}, 'json');
}
```
这样有一个很大的问题:多个异步去修改同一全局变量,必须要锁定全局变量 oldcontent ,不然只有最后 i 循环 修改 oldcontent 生效。
请高手支招?
6006 次点击
所在节点    JavaScript
83 条回复
wingzhingling
300 天前
给定一个长字符串 oldContents 和一个数组 allImg[]。oldContents 中包含一些图片地址,数组中的每一项为一个需要替换的图片地址字符串。使用 post 请求发送需要替换的图片地址,会返回替换后的图片地址。
现在需要将 oldContents 中出现的每一个 allImg[]中的图片地址都替换为新的地址。
wingzhingling
300 天前
要替换 `oldContents` 中的图片地址,您可以使用以下 JavaScript 代码作为参考。这段代码假设您已经有了一个函数 `replaceImageUrl`,它会发送 POST 请求并返回新的图片地址。

```javascript
async function replaceAllImages(oldContents, allImg) {
// 使用 map 函数异步替换所有图片地址
const replacePromises = allImg.map(async (img) => {
const newImg = await replaceImageUrl(img); // 假设这个函数发送 POST 请求并返回新地址
oldContents = oldContents.replace(img, newImg); // 替换图片地址
});

// 等待所有图片地址替换完成
await Promise.all(replacePromises);

// 返回替换后的内容
return oldContents;
}

// 假设的 replaceImageUrl 函数,您需要根据实际情况实现它
async function replaceImageUrl(url) {
// 发送 POST 请求并获取新的图片地址
// 这里需要您根据实际的 API 接口来实现
const response = await fetch('您的 API 端点', {
method: 'POST',
body: JSON.stringify({ imageUrl: url }),
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
return data.newImageUrl; // 假设返回的数据中包含新的图片地址
}
```

请确保您的服务器端点能够处理 POST 请求,并且返回所需的新图片地址。您可能需要根据您的具体 API 和返回的数据格式调整 `replaceImageUrl` 函数的实现细节。如果您需要进一步的帮助,请告诉我!
abccccabc
300 天前
@cheese 谢谢。

代码正在改造中
vituralfuture
300 天前
JS 单线程➕事件循环,绝大部分情况下不会出现竞态条件,因为
1. 同一时刻只有一个任务在运行
2. 任务交出 CPU 的时机可控

如果还是出现了竞态条件,也不应该用锁 因为锁抢走了事件循环对线程的控制权

我在用和 JS 一样单线程➕事件循环的 dart 时也遇到过类似问题,使 dart 提供的 Compeleter 即可
zzxqd
300 天前
@zzxqd 你在循环外部定义的 content, 每次 replace 时的值都是当前最新的值,只是顺序不可控而已,你要想等所有请求结束后,去使用这个 content 的话,定义一个计数器 var reqCount = allimg.length 也就是你请求中的数量,每次请求完成(成功或者失败后),
reqCount -= 1
if (reqCount === 0) {
console.log(content)
}
Ritr
300 天前
var i 改为 let i
musi
300 天前
首先,js 是单线程的,不会存在竞争锁之类的东西
jones2000
300 天前
改同步, 不用异步, 用 woker 后台下。
Plumbiu
300 天前
@qrobot 不太理解为啥是闭包
qrobot
300 天前
@Plumbiu 这个和闭包关系也不是很大, 准确来说是异步回调和闭包组合起来产生的问题, 你让她把 $.post 改成阻塞的代码逻辑就是正常的.
qrobot
300 天前
@Plumbiu 我写代码很多年以前就不会这么写了.

例如


```
[].forEach(async(ele) => await asyncFunction(ele))
```

类似这中在循环中调用方法的. 虽然逻辑是对的,但是却没有很好使用 async/await, 实际上是把异步任务转换成为同步任务. 并不是并发执行的任务, 而是同步执行的任务. 性能上差很多
Plumbiu
300 天前
我的理解是,var 不存在块级作用域,如果 oldcontent 写在 for 循环内部,那么就相当于创建了很多次 oldcontent ,就像下面这样

```js
for (var i = 0; i < 100; i++) {
var a = 200
a = a - i
}
// 等同于
var a;
// 第一次循环
a = 200
a = a - 0
// 第二次循环
a = 200
a = a - 1
// ....
// 第一百次循环
a = 200
a = a - 99
```

所以只有最后一次生效了
Plumbiu
300 天前
@qrobot forEach 不能用 async/await 的,我的理解就是作用域问题,看我上一个回答
MrDarnell
300 天前
一个锁的事情
Leviathann
300 天前
再三确认没看到哪里用了 i
wangtian2020
300 天前
```
;(async()=>{
let allimg = 获取到的图片数组
let oldcontent = 原内容
for (var i = 0; i < allimg.length; i++) {
let ret = await $.post(
'url',
参数,
'json'
)
if (ret['code'] == 200) {
oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl'])
} else {
console.log(错误信息)
}

}
})()
```
我示意的写一下,给你的代码的几个只有好处没有坏处的建议
把所有的 var 替换成 let ;所有函数替换成箭头函数;使用 promise 风格的请求库,都什么年代了不要用回调函数风格的方法了
qrobot
300 天前
@Plumbiu 并不是, 你第一个代码的含义其实是这个

```
let a

for (var i = 0; i < 100; i++) {
a = 200 - i
}

```

forEach 不能用 async/await 的原因不是因为闭包问题
wangtian2020
300 天前
```
;(async()=>{
let allimg = 获取到的图片数组
let oldcontent = 原内容
for (let i = 0; i < allimg.length; i++) {
let ret = await $.post(
'url',
参数,
'json'
)
if (ret['code'] == 200) {
oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl'])
} else {
console.log(错误信息)
}

}
})()
```

for 循环中的 var 忘记改了。for 后的临时变量赋值千万不能用 var
ming159
300 天前
循环内部改造成函数调用就行了.....
`
var allimg = 获取到的图片数组;
var oldcontent = 原内容;
for(var i=0; i<allimg.length; i++){
var url = allimg[i]
doReplace(url); // 函数调用传值作用域会改变
}
function doReplace(url){
$.post('url', 参数, function(ret) {
if(ret['code'] == 200) {
oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl']);
}else{
console.log(错误信息);
}
}, 'json');
}

`
qrobot
300 天前
@Plumbiu 按照他的代码执行下去,那么就应该是

```
let a = ''

for (let i = 0; i < 100; i++) {
// 每次都会生效
a = a.replace(`${i}`, `test-${i}`)
}


```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1024619

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX