调查JavaScript线程性能
线程状态可视化让您可以将线程在应用生命周期中所处状态可视化。它可以帮助您排除故障,优化您的JavaScript (JS) 应用的性能。
要有效地使用线程状态可视化,请遵循此页面上的指南。
了解线程状态
线程可以各种状态存在,例如Running(正在运行)、Runnable(可运行)、Runnable (Preempted)(可运行(被抢占))、Sleeping(休眠)、Uninterruptible Sleep(不间断休眠)、Stopped(已停止)、Idle(空闲)和Exit(退出)。有关每种状态的确切定义,请参阅监控和记录您的应用性能中的“线程状态”。
确定性能问题的原因
线程状态可视化可以提供有关应用性能问题的见解,例如延迟增加、无响应、崩溃和行为不一致。下表列出了一些可能的性能问题原因,这些原因可以使用线程状态信息来识别。
| 原因 | 描述 | 相关线程状态 |
|---|---|---|
| 线程长时间运行 | 如果线程长时间保持“Running”状态,可能表示处理效率低下或操作长时间运行,可通过优化来改善此状况。 | Running |
| CPU使用率过高 | 许多线程主动处于“Running”状态的情况,这可能表明算法效率低下或上下文切换过多,从而导致资源紧张。 | Running、Runnable |
| CPU争用 | 当多个线程争夺有限的CPU资源时,就会出现严重争用情况。这可能导致线程被抢占或等待访问共享资源。 | Runnable (Preempted) |
使用Vega Studio性能扩展
Vega Studio性能扩展 (KSPE) 在Activity Monitor和Memory Monitor的Recording(记录)视图中提供线程状态可视化。要解决JS应用中的性能问题,请完成以下步骤:
- 在Activity Monitor中开始记录。
- 在应用中再现有问题的行为。
- 停止录制以生成Recording视图,其中包括带有线程状态信息的Traces(跟踪)视图。
分析线程状态数据
要确定应用性能问题,请执行以下操作:
- 在Traces视图中分析线程状态数据。
- 检查线程状态数据是否与前面提到的任何原因相对应:线程长时间运行、CPU使用率过高或CPU争用。
使用案例
以下示例显示线程状态可视化如何帮助用户排除故障和优化应用性能。
使用案例1: 排除由于算法效率低下而导致的线程长时间运行故障
在测试VegaVideoApp时,您在调出主屏幕或任何详情页面时遇到了响应不佳的问题。
为了确定问题,您再现了应用中有问题的行为,同时在Activity Monitor中启动了记录。当记录停止时,Activity Monitor会生成一个Recording视图,包括带有线程状态信息的Traces视图。您检查了Traces,其中显示JS线程运行了长达5秒钟。这表明由于算法效率低下,线程长时间运行。
您检查了CPU分析器火焰图,由于getClassics方法,其中DetailsScreen花费了5秒钟。
在重新审视应用代码时,您注意到在对数据进行排序和筛选时代码效率低下,从而导致性能延迟问题。
export const getClassics = (): TitleData[] => {
const classics = [
{
id: '169327',
title: 'Ethereal Echos',
description: 'Lorem ipsum dolor sit amet',
mediaType: 'video',
mediaSourceType: 'url',
duration: 300,
thumbnail: tile09,
posterUrl: tile09,
videoUrl:
'https://edge-vod-media.cdn01.net/encoded/0000169/0169313/video_1880k/T7J66Z106.mp4?source=firetv&channelID=13454',
categories: ['Hits'],
channelID: '13455',
rating: '5',
releaseDate: '09/20',
format: 'MP4',
uhd: false,
secure: false,
rentAmount: '200',
},
...
...
];
// 排序效率低下
const sortClassics = (array: TitleData[]): TitleData[] => {
const n = array.length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n - i - 1; j++) {
for (let k = 0; k < n; k++) {
if (array[k].title === 'NA') {
continue;
}
}
if (array[j].title.localeCompare(array[j + 1].title) > 0) {
// 如果当前元素大于下一个元素,则交换。
const temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
return array;
};
// 使用嵌套循环进行筛选,效率低下。
const filterClassics = (array: TitleData[], category: string): TitleData[] => {
const result: TitleData[] = [];
for (let i = 0; i < array.length; i++) {
let found = false;
for (let j = 0; j < array.length; j++) {
if (array[i].categories.includes(category) && array[i] === array[j]) {
found = true;
break;
}
}
}
return result;
};
const sortedClassics = sortClassics(classics);
const filteredClassics = filterClassics(sortedClassics, 'Hits');
return filteredClassics;
};
要解决这个问题,您可以删除不必要的嵌套循环。然后,重新访问Traces视图以验证您的应用性能是否有所改善。
使用案例2: 解决滚动应用中CPU使用率过高的问题
使用React Native Flatlist组件(仅提供英文版)创建一个简单的滚动应用,用不同的颜色显示200行。使用Activity Monitor,您在滚动期间观察到线程状态视图中频繁出现“Running”状态,这表明CPU使用率过高。CPU分析器火焰图也显示出高活动性,这表明Flatlist组件的运行效率低下。
以下示例代码显示了如何在应用中添加Flatlist组件。
const PerfFlatListApp = () => {
// https://reactnative.dev/docs/optimizing-flatlist-configuration#avoid-anonymous-function-on-renderitem
const renderItem = useCallback(
({ item, index }: { item: FlatListItem; index: number }) => (
// https://reactnative.dev/docs/optimizing-flatlist-configuration#use-basic-components
<Item
key={item.title}
buttonStyle={[
styles.item,
{
backgroundColor: calculateBackgroundColor(index)
}
]}
hasTVPreferredFocus={item.id === 0}
/>
),
[]
);
// https://reactnative.dev/docs/optimizing-flatlist-configuration#use-keyextractor-or-key
const keyExtractor = useCallback(
(item: FlatListItem, index: number) => item.title,
[]
);
// https://reactnative.dev/docs/optimizing-flatlist-configuration#use-getitemlayout
const getItemLayout = useCallback(
(
_data: any,
index: number
): { length: number; offset: number; index: number } => ({
index,
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index
}),
[]
);
useEffect(() => {
console.log('reporting fully_drawn');
// @ts-ignore
global.performance.reportFullyDrawn();
}, []);
return (
<View style={styles.container}>
<FlatList
data={data}
renderItem={renderItem}
// https://reactnative.dev/docs/optimizing-flatlist-configuration#initialnumtorender
// 明确将其设置为10,因为这是屏幕上可查看项目的初始数量。
initialNumToRender={10}
keyExtractor={keyExtractor}
getItemLayout={getItemLayout}
// https://reactnative.dev/docs/optimizing-flatlist-configuration#windowsize,
// 将MM上的窗口大小设置成高于电视配置文件上的大小,因为通过快速触摸
// 滑动来滚动Flatlist时,速度会比按住方向键进行滚动更快。窗口大小
// 越大,占用内存越多,但会减少滚动时看到的空白区域。
windowSize={Platform.isTV ? 5 : 13}
/>
</View>
);
};
为了解决性能问题,可以用Shopify的Flashlist组件替换Flatlist组件,前者旨在提高滚动场景中的性能。
const PerfFlashListApp = () => {
// https://reactnative.dev/docs/optimizing-flatlist-configuration#avoid-anonymous-function-on-renderitem
const renderItem = useCallback(
({ item, index }: { item: FlashListItem; index: number }) => (
// https://reactnative.dev/docs/optimizing-flatlist-configuration#use-basic-components
<Item
buttonStyle={[
styles.item,
{
backgroundColor: calculateBackgroundColor(index)
}
]}
hasTVPreferredFocus={item.id === 0}
/>
),
[]
);
// https://reactnative.dev/docs/optimizing-flatlist-configuration#use-keyextractor-or-key
const keyExtractor = useCallback(
(item: FlashListItem, index: number) => item.title,
[]
);
useEffect(() => {
console.log('reporting fully_drawn');
// @ts-ignore
global.performance.reportFullyDrawn();
}, []);
return (
<View style={styles.container}>
<FlashList
estimatedItemSize={ITEM_HEIGHT}
data={data}
renderItem={renderItem}
keyExtractor={keyExtractor}
/>
</View>
);
};
重新测试应用的性能,并验证线程状态视图中的“Running”状态的数量是否有所减少。CPU分析器火焰图还应显示活动减少。
要了解Flashlist相较于Flatlist的优势,请参阅最佳实践。
相关主题
Last updated: 2025年9月30日

