Javascript 为什么分拣会立即完成?
我一直在尝试使用react显示数组排序过程的每个步骤。 我已经实现了冒泡排序算法,但我注意到一件非常奇怪的事情: 当我使用这种方法时,UI会立即显示排序的数组:Javascript 为什么分拣会立即完成?,javascript,reactjs,Javascript,Reactjs,我一直在尝试使用react显示数组排序过程的每个步骤。 我已经实现了冒泡排序算法,但我注意到一件非常奇怪的事情: 当我使用这种方法时,UI会立即显示排序的数组: function BubbleSort({ array }) { const [elements, setElements] = useState(array); const onSort = () => { console.log('onSort fired') const length = eleme
function BubbleSort({ array }) {
const [elements, setElements] = useState(array);
const onSort = () => {
console.log('onSort fired')
const length = elements.length;
const newElements = elements.slice();
let swap = 0;
for (let i = 0; i < length; i++) {
for (let j = i + 1; j < length; j++) {
if (newElements[i].value > newElements[j].value) {
console.log('Swap fired', swap);
const buffer = newElements[i];
newElements[i] = newElements[j];
newElements[j] = buffer;
swap++
setTimeout(() => setElements(newElements.slice()), 1000 * swap);
}
}
}
}
return (
<ArrayView elements={elements} onSort={onSort}/>
);
}
函数BubbleSort({array}){
const[elements,setElements]=useState(数组);
常量onSort=()=>{
console.log('onSort-fired')
常量长度=elements.length;
const newElements=elements.slice();
设swap=0;
for(设i=0;inewElements[j].value){
log('Swap-fired',Swap);
常量缓冲区=新元素[i];
新元素[i]=新元素[j];
新元素[j]=缓冲区;
交换++
setTimeout(()=>setElements(newElements.slice()),1000*swap);
}
}
}
}
返回(
设置超时
是非阻塞的
在第一个代码示例中,您在排序过程的每个步骤后都设置了一个超时。但是,这并不会导致代码暂停和等待,而是会安排回调在以后发生。因此,您的代码将继续并执行排序的下一步,然后安排另一个回调,依此类推。经过1秒后,回调将触发,但数组已完成排序,因此UI将更改为完全排序的数组
在第二个示例中,您存储了步骤并将超时间隔适当地触发。回调不查看数组的全局状态,而是查看每个事件并按预期播放它们
编辑:处理您的评论
调用slice
会创建数组的副本,这是正确的。问题是您在调度回调后调用slice
创建arrow函数时,会捕获其作用域中的变量,但在调用函数之前不会计算其中的代码。在这种情况下,1秒后,它将调用newElements.slice()
并将其传递给setElements
。此时,newElements
已被排序,所有副本看起来都一样
你可以用两种方法来解决这个问题。第一种方法是按照你在评论中提到的去做。我个人觉得这很难理解。另一种方法是立即调用slice
,并在回调中使用该值
const newElementsCopy = newElements.slice();
setTimeout(() => setElements(newElementsCopy), 1000 * swap);
当计时器在第一秒内等待触发时,循环结束。当计时器功能运行时(第一次),newElements
是完全排序的。如果我在使用slice
函数时理解正确,它会创建数组的新副本。因此,在每一步中,我都会在timer函数中传递一个新数组。谢谢,我得到了它!我只需要将数组的副本传给回调,如下所示:setTimeout((copyOfArray)=>setElements(copyOfArray),1000*swap,copyOfArray)
@RomanAndreev更新了我的答案,以更明确地解决这个问题。在重新阅读您的问题和我的编辑后,我意识到我的初始答案有点偏离了基准。问题与调用切片的位置有关,而不是设置超时。
const newElementsCopy = newElements.slice();
setTimeout(() => setElements(newElementsCopy), 1000 * swap);