【发布时间】:2025-12-16 10:40:02
【问题描述】:
大家好
我正在使用React Native,我想添加一些功能,用户可以将多个文件导入我的应用程序,并且用户可以随时取消导入进度
但是,当用户导入这些文件的时候,我要一个一个地导入,告诉用户哪些文件已经导入成功,哪些文件没有导入,
这对我很重要,因为我想告诉用户有多少已选择的文件已成功导入,并且对于在导入该文件时向 UI 显示每个文件很有用,这需要我使用 @987654324 @,
问题是我不知道如何取消使用Recursive Functions、I try with makeCancelable method from react site 的Promise 它不起作用,我认为它只是取消了Promise在树的顶部Recursive Functions,并非所有已执行的 Promise。另外,如果可能的话,我不想使用任何 deps/packages。 有什么想法吗?
核心工具
使用真机Xiaomi Redmi 1S 4.4 Kitkat
"react": "16.13.1",
"react-native": "0.63.3",
代码示例
importFiles.js
import RNFetchBlob from 'rn-fetch-blob';
import CameraRoll from '@react-native-community/cameraroll';
import _ from 'lodash';
const fs = RNFetchBlob.fs;
/**
* Import directory destination
*/
const dest = `${fs.dirs.SDCardDir}/VEGA/.src/`;
/**
* An increment index to tell the function which index to run
*/
let i = 0;
/**
* Import the files to this App with some encryption
* @param {object} config
* @param {string} config.albumId
* @param {[{
* uri: string,
* mimeType: string,
* albumName: string,
* timestamp: number,
* isSelected: boolean,
* }]} config.files
* @param {'fake' | 'real'=} config.encryptionMode
*/
const importFiles = config => {
return new Promise(async (resolve, reject) => {
const {albumId, files, encryptionMode} = config;
if (_.isEmpty(files) || !_.isArray(files)) {
reject('invalid files');
return;
}
const file = files[i];
/**
* It's mean Done when the file got "undefined"
*/
if (!file) {
resolve();
return;
}
const uri = file.uri.replace('file://', '');
try {
/**
* Fake Encryption
*
* It's fast but not totally secure
*/
if (!encryptionMode || encryptionMode === 'fake') {
const md5 = await fs.hash(uri, 'md5');
const importedFileUri = `${dest}.${md5}.xml`;
/**
* TODO:
* * Test cancelable
*/
await fs.readFile(uri, 'base64');
// await fs.mv(uri, importedFileUri);
// await CameraRoll.deletePhotos([uri]);
/**
* If successfully import this file then continue it to
* the next index until it's "undefined"
*/
i++;
}
/**
* Real Encryption
*
* It's slow but totally secure
*/
if (encryptionMode === 'real') {
}
await importFiles({files, encryptionMode}).promise;
resolve();
} catch (error) {
reject(error);
}
});
};
export default importFiles;
FileImporter.js(我如何使用makeCancelable方法)
import React, {useEffect} from 'react';
import {View, Alert} from 'react-native';
import {Contrainer, TopNavigation, Text} from '../components/Helper';
import {connect} from 'react-redux';
import utils from '../utils';
const makeCancelable = promise => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
val => (hasCanceled_ ? reject({isCanceled: true}) : resolve(val)),
error => (hasCanceled_ ? reject({isCanceled: true}) : reject(error)),
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
const FileImporter = props => {
const {userGalleryFiles} = props;
useEffect(() => {
props.navigation.addListener('beforeRemove', e => {
e.preventDefault();
Alert.alert(
'Cancel?',
'Are you sure want to cancel this?',
[
{text: 'No', onPress: () => {}},
{
text: 'Yes!',
onPress: () => props.navigation.dispatch(e.data.action),
},
],
{cancelable: true},
);
});
(async () => {
const selectedFiles = userGalleryFiles.filter(
file => file.isSelected === true,
);
try {
await makeCancelable(utils.importFiles({files: selectedFiles})).promise;
console.warn('Oh God!!!');
} catch (error) {
console.error(error);
}
return () => makeCancelable().cancel();
})();
}, []);
return (
<Contrainer>
<TopNavigation title='Importing files...' disableIconLeft />
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text hint>0 / 20</Text>
</View>
</Contrainer>
);
};
const mapStateToProps = ({userGalleryFiles}) => ({userGalleryFiles});
export default connect(mapStateToProps)(FileImporter);
预期结果
importFiles.js 可以在卸载FileImporter.js 时取消
实际结果
importFiles.js 仍在运行,即使 FileImporter.js 已卸载
【问题讨论】:
-
只需在每个异步 (
awaited) 步骤之前检查has_canceled变量即可。 -
@Bergi 谢谢你的评论,但我还是没听懂你在说什么check
hasCanceled_variable
标签: javascript reactjs react-native promise cancellation