无法在IPCRenderer中传递对象/数组,无法克隆对象EventEmitter.i.send.i.send [英] Unable To Pass Objects/Arrays in IPCRenderer, An object could not be cloned EventEmitter.i.send.i.send

查看:311
本文介绍了无法在IPCRenderer中传递对象/数组,无法克隆对象EventEmitter.i.send.i.send的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法将任何对象或数组传递给IPCRenderer.

通过ipcs传递对象或数组时出现错误,我什至尝试通过使用JSON.stringify转换为字符串进行发送,但它将其转换为空的对象字符串.

我尝试传递fileList,对象数组&即使是一个物体也不会通过.仅字符串或手写对象有效.

我已经了解到它使用结构化克隆算法和fileList&该算法允许使用数组

错误:

  electron/js2c/renderer_init.js:74未捕获错误:无法克隆对象.在EventEmitter.i.send.i.send(electron/js2c/renderer_init.js:74)在HTMLButtonElement.compressNow(ImageHandling.js:190) 

我尝试了许多可能的解决方案,但没有任何效果

代码:

 const compressNow =()=>{ipcRenderer.send("image:compress",文件).///这是错误.//filess是一个变量,其中包含HTML输入中所选文件的数组.} 

现在,我尝试以 JSON.stringify 的形式发送文件,我尝试以对象的形式发送文件,但除非手动编写虚拟对象或字符串,否则任何方法都无效.

这是我的此项目的Github存储库

错误文件 J:-

ImageHandling.js

  const fs = window.require('fs');const {ipcRenderer} = require(电子")const SELECT =(target)=>document.querySelector(`$ {target}`)var filess = []const imgUploadInput = SELECT(#imgUploadInput")const warning = SELECT(#warning")const setImgBase64 =(imgEl,文件)=>{const ReadAbleFile = fs.readFileSync(file.path).toString('base64')令src ="data:image/png; base64,"+ ReadAbleFileimgEl.setAttribute("src",src)//El.src = src//console.log(`FIXED IMAGE#$ {imgEl}`,ReadAbleFile)}const renderImages =()=>{const文件=文件&&Array.from(filess)const defaultImg = SELECT(#defaultImg")const addImgBtn = SELECT(#addImgBtn")imgUploadInput.disabled = true;让numOfFiles = files.length如果(numOfFiles< 1){SELECT(#compressContainer").style.visibility ="hidden"} 别的 {SELECT(#compressContainer").style.visibility ="visible";}如果(numOfFiles> 49){warning.innerHTML =`< b style =" font-weight:bold;颜色:红色;"警告:</b> br/>< span style =" padding:10px; text-align:left">您的处理器/计算机可能无法一次处理$ {numOfFiles}个图像,我们建议一次选择少于50个图像,以获得更好的性能.</span>`;}addImgBtn.innerHTML =`正在加载.....`如果(defaultImg&& numOfFiles> 0)defaultImg.remove();setTimeout(()=> {if(文件&& numOfFiles> 0){让displayImages = SELECT(#displayImages")displayImages.innerHTML ="文件?forEach((file,i)=> {让divEl = document.createElement("div")让imgEl = document.createElement("img")imgEl.src = file.pathimgEl.id =`PNG _ $ {i} _ $ {btoa(文件名)}`divEl.className ="displayedImg"imgEl.setAttribute("onclick",`document.getElementById('ImageView').src = this.src`)const a = document.createElement("a")a.appendChild(imgEl)a.setAttribute("href",`#ViewImage`)a.className ="perfundo__link";divEl.appendChild(a)divEl.className ="displayedImg perfundo";displayImages.appendChild(divEl)如果(i == files.length-1){warning.innerHTML =&";updateNumOfImages();}imgEl.onerror =()=>setImgBase64(imgEl,file)//仅在出错时转换为base64,这可以提高性能并帮助我们避免冻结.(在此之前,我将所有图像都转换为错误或没有错误的base64,这使计算机变得freez)})addImgBtn.innerHTML ="+添加更多"imgUploadInput.disabled = falsefindDuplicate()}},0);}const hasDuplicate =()=> {让FileNames = [... files.map(f => f.name)]让repeatFiles = filess.filter((file,i)=> FileNames.indexOf(file.name)!== i)返回{FileNames,duplicateFiles,FilesLength:duplicateFiles.length}}const findDuplicate =(forceAlert = false)=>{if(files&& files.length){让{FileNames} = hasDuplicate()让{duplicateFiles} = hasDuplicate()如果(duplicateFiles.length){//alert(``)让countFiles = plicateFiles.length让fileStr = countFiles>1个文件":文件";console.log("removeDup =>的结果,",文件,"\ n dupfilename =","FileNames","\ n dupfiles =>,",重复文件)让shouldNotAsk = localStorage.getItem("NeverAsk")let msg =`您已选择$ {countFiles>1个countFiles:"a";}复制$ {fileStr}`让duplInner =`< span style ='color:red'>< b>警告</b>< p style =" margin:0px; line-height:1">$ {msg}.< button onClick ="findDuplicate(true)";type ="button"class ="btn btn-danger btn-rounded btn-sm">删除重复"//按钮.</span>`如果(!shouldNotAsk || forceAlert){swal("DUPLICATE FILES DETECTED",`$ {msg},是否要取消选择具有相同名称的重复$ {fileStr}?,{图标:警告",angersMode:真,纽扣: {取消:是的,... forceAlert?{}:{永不:永不询问";},确认:是!";}}).then((Yes)=> {如果(是==从不"){localStorage.setItem("NeverAsk",true)warning.innerHTML = duplInner}否则,如果(是){removeDuplicates()}})} 别的 {warning.innerHTML = duplInner}}}}const removeDuplicates =(showAlert = true)=>{让{FileNames} = hasDuplicate()让{duplicateFiles} = hasDuplicate()让plicateFileNames = plicateFiles.map(f => f.name)让uniqueFiles = filess.filter((file)=>!plicateFileNames.includes(file.name))文件=... uniqueFiles,...重复文件]console.log("removeDup =>的结果,",文件,"\ n filename =","FileNames","\ n dupfiles =>",重复文件,"\ n unique fil =>",uniqueFiles)renderImages()如果(showAlert){swal("DONE",已删除重复文件",{icon:'success'}).then(()=> {renderImages()setTimeout(()=> {让hasDuplicateFiles = hasDuplicate().FilesLengthif(hasDuplicate){//重新检查在当前删除过程之后是否还有重复的文件.removeDuplicates(false)//重新运行该函数以删除剩余部分.false将确保不显示此警报,并且循环不会继续.}renderImages()},10);})}}const updateNumOfImages =()=>{warning.innerHTML =`< span style =""text-align:left;颜色:绿色选定的$ {files.length} 图片)</span>`;}const compressNow =()=>{ipcRenderer.send("image:compress",文件)//警报("WOW")}CompressBtn.addEventListener("click",compressNow)imgUploadInput.addEventListener("change",(e)=> {让SelectedFiles = e.target.files如果(SelectedFiles& SelectedFiles.length){文件=...文件,... SelectedFiles]renderImages()}})//SELECT(#imgUploadInput").addEventListener("drop" ,,(e)=> console.log("DROP =>",e)) 

更新:-

我替换了此

  const compressNow =()=>{ipcRenderer.send("image:compress",filess)} 

这是:-

  const compressNow =()=>{files.forEach(file => {ipcRenderer.send("image:compress",file.path)});} 

现在,这里我是通过forEach逐个发送文件,实际上是它的发送字符串"file path".所以多数民众赞成在其如何工作,我仍然感到困惑,为什么我必须这样做?为什么我不能发送整个fileList我认为这种循环方法是一种不好的做法,因为它将消耗更多的CPU和一个额外的循环,但是如果我能够发送整个数组,则不必这样做.

解决方案

请参见

在您的代码中, 文件 FileList 是DOM对象.

如果要避免使用 forEach ,请尝试以下代码:

  const compressNow =()=>{const path = filess.map(f => f.path);ipcRenderer.send("image:compress",路径);} 

I am unable to pass any object or arrays to IPCRenderer.

I am getting error when passing an object or array through ipcs, I have even tried to send by converting to string using JSON.stringify but it converts it into empty object string.

I have tried passing a fileList, an array of object & even an object nothing passes. only string or handwritten objects are working.

I've read that it uses Structured Clone Algorithm and fileList & Array is allowed by this algorithm

ERROR:

electron/js2c/renderer_init.js:74 Uncaught Error: An object could not be cloned.
    at EventEmitter.i.send.i.send (electron/js2c/renderer_init.js:74)
    at HTMLButtonElement.compressNow (ImageHandling.js:190)

I have tried many possible solutions but nothing worked

code:


const compressNow = () => {
    ipcRenderer.send("image:compress", filess).  ///This is the error.
    // filess is a variable containing an array of selected files from an HTML input.
}

Now i have tried to send filess as JSON.stringify, i tried to send it as an object but nothing works unless i manually write a dummy object or string.

Here's My Github Repo for this project

Files With ErrorJ:-

ImageHandling.js

const fs = window.require('fs');
const {ipcRenderer} = require("electron")
const SELECT = (target) => document.querySelector(`${target}`)
var filess = []

const imgUploadInput = SELECT("#imgUploadInput")
const warning = SELECT("#warning")

const setImgBase64 = (imgEl, file) => {

    const ReadAbleFile = fs.readFileSync(file.path).toString('base64')
    let src = "data:image/png;base64," + ReadAbleFile

    imgEl.setAttribute("src", src)
    // El.src=src

    // console.log(`FIXED IMAGE # ${imgEl} `,ReadAbleFile)

}
const renderImages = () => {
    const files = filess && Array.from(filess)
    const defaultImg = SELECT("#defaultImg")
    const addImgBtn = SELECT("#addImgBtn")
    imgUploadInput.disabled = true;

    let numOfFiles = files.length

    if (numOfFiles < 1) {
        SELECT("#compressContainer").style.visibility = "hidden"
    } else {
        SELECT("#compressContainer").style.visibility = "visible"
    }
    if (numOfFiles > 49) {
        warning.innerHTML = `<b style="font-weight:bold; color:red;">WARNING:</b><br/> 
                               <span style="padding:10px;text-align:left">
                               Your processor/computer may not be able to process ${numOfFiles} Images at once, We recommend selecting less than 50 Images at once for better performance.
                                </span>
                                `;
    }
    addImgBtn.innerHTML = `LOADING.....`
    if (defaultImg && numOfFiles > 0) 
        defaultImg.remove();
    


    setTimeout(() => {

        if (files && numOfFiles > 0) {
            let displayImages = SELECT("#displayImages")
            displayImages.innerHTML = ""
            files ?. forEach((file, i) => {
                let divEl = document.createElement("div")
                let imgEl = document.createElement("img")
                imgEl.src = file.path

                imgEl.id = `PNG_${i}_${
                    btoa(file.name)
                }`
                divEl.className = "displayedImg"

                imgEl.setAttribute("onclick", `document.getElementById('ImageView').src=this.src`)


                const a = document.createElement("a")
                a.appendChild(imgEl)

                a.setAttribute("href", `#ViewImage`)
                a.className = "perfundo__link"


                divEl.appendChild(a)

                divEl.className = "displayedImg perfundo"

                displayImages.appendChild(divEl)


                if (i == files.length - 1) {
                    warning.innerHTML = "";
                    updateNumOfImages();
                }
                imgEl.onerror = () => setImgBase64(imgEl, file) // converting to base64 only on error, this make performance better and help us avoid freezes. (before this i was converting all images to base64 wither errored or not that was making computer freez)
            })
            addImgBtn.innerHTML = "+ Add MORE"
            imgUploadInput.disabled = false
            findDuplicate()
        }

    }, 0);
}

const hasDuplicate=()=>{
    let FileNames = [... filess.map(f => f.name)]
    let duplicateFiles = filess.filter((file, i) => FileNames.indexOf(file.name) !== i)

    return {FileNames,duplicateFiles,FilesLength:duplicateFiles.length}
}
const findDuplicate = (forceAlert = false) => {
    if (filess && filess.length) {
        let {FileNames} = hasDuplicate()
        let {duplicateFiles} = hasDuplicate()
        if (duplicateFiles.length) { // alert(``)

            let countFiles = duplicateFiles.length
            let fileStr = countFiles > 1 ? "files" : "file"
            console.log("result from removeDup=> ", filess, " \n dupfilename=> ", FileNames, " \n dupfiles=> ", duplicateFiles)

            let shouldNotAsk = localStorage.getItem("NeverAsk")
            let msg = `You've selected ${
                countFiles > 1 ? countFiles : "a"
            } duplicate ${fileStr}`
            let duplInner = `<span style='color:red'> 
                               <b>WARNING</b>
                               <p style="margin:0px;line-height:1">  ${msg} .  <button onClick="findDuplicate(true)" type="button"  class="btn btn-danger btn-rounded  btn-sm">REMOVE DUPLICATE</button></p>
                              </span>`
            if (! shouldNotAsk || forceAlert) {
                swal("DUPLICATE FILES DETECTED", `${msg} , Would you like to un-select duplicate ${fileStr} having same name?`, {
                    icon: 'warning',
                    dangerMode: true,
                    buttons: {
                        cancel: true,
                        ...forceAlert ? {} : {
                            never: "Never Ask"
                        },
                        confirm: "Yes !"
                    }
                }).then((Yes) => {
                    if (Yes == "never") {
                        localStorage.setItem("NeverAsk", true)
                        warning.innerHTML=duplInner

                    } else if (Yes) {
                        removeDuplicates()

                    }
                })
            } else {
                warning.innerHTML=duplInner
            }
        }

    }
}


const removeDuplicates = (showAlert=true) => {
    
    let {FileNames} = hasDuplicate()
    let {duplicateFiles} = hasDuplicate()
    let duplicateFileNames = duplicateFiles.map(f => f.name)
    let uniqueFiles = filess.filter((file) => ! duplicateFileNames.includes(file.name))
    filess = [
        ... uniqueFiles,
        ... duplicateFiles
    ]

    console.log("result from removeDup=> ", filess, " \n filename=> ", FileNames, " \n dupfiles=> ", duplicateFiles, "\n unique fil=> ", uniqueFiles)
    renderImages()
    if(showAlert){
    swal("DONE", "Removed Duplicate Files ", {icon: 'success'}).then(() =>{ 
        renderImages()
        setTimeout(() => {
             let hasDuplicateFiles = hasDuplicate().FilesLength
             if(hasDuplicate){//Re-check if any duplicate files left after the current removal process. 
                 removeDuplicates(false) //Re-run the function to remove remaining. false will make sure that this alert does not show and the loop does not continue.
             }
             renderImages()

        }, 10);
    
    })
   }
}




const updateNumOfImages = () => {
    warning.innerHTML = `
                <span style="text-align:left; color:green">
                        Selected ${
        filess.length
    } Image(s)
                 </span>
                 `;
}


const compressNow = () => {
    ipcRenderer.send("image:compress", filess)
    // alert("WOW")
}


CompressBtn.addEventListener("click", compressNow)

imgUploadInput.addEventListener("change", (e) => {
    let SelectedFiles = e.target.files

    if (SelectedFiles && SelectedFiles.length) {
        filess = [
            ... filess,
            ... SelectedFiles
        ]
        renderImages()
    }
})
// SELECT("#imgUploadInput").addEventListener("drop",(e)=>console.log("DROP=> ",e))

UPDATE:-

I REPLACED THIS:

const compressNow = () => {

        ipcRenderer.send("image:compress",filess)
    
}

INTO THIS:-

const compressNow = () => {

    filess.forEach(file => {
        ipcRenderer.send("image:compress",file.path )
    });
}

Now here i am sending the files one by one via forEach, actually its sending string "file path" so thats how its working i am still confused why do i have to do this? why can't i send whole fileList i assume that this loop method is a bad practice because it will consume more CPU its one additional loop however it won't be necessary if i am able to send the whole array.

解决方案

See Behavior Changed: Sending non-JS objects over IPC now throws an exception. DOM objects etc. are not serializable. Electron 9.0 (and newer) throws "object could not be cloned" error when unserializable objects are sent.

In your code, File and FileList are DOM objects.

If you want to avoid using forEach, try this code:

const compressNow = () => {
    const paths = filess.map(f => f.path);
    ipcRenderer.send("image:compress", paths);
}

这篇关于无法在IPCRenderer中传递对象/数组,无法克隆对象EventEmitter.i.send.i.send的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆