簡體   English   中英

我如何等待更新 HTML 標頭,直到解決承諾?

[英]How do I wait to update an HTML header until promise is resolved?

我正在構建我的第一個電子應用程序,我遇到了一個 JS 錯誤,我不知道如何修復。 我已經設法為一個基本的密碼管理器應用程序設置了 IPC。 用例很簡單:

  1. 我單擊一個 HTML 按鈕,前端連接到后端並提供一個關鍵字來構建密碼。
  2. 生成密碼。
  3. 完成后,密碼將返回到前端,以通過 HTML 的標題標簽顯示。

以下是輸入字符串 dog 的預期行為示例:
關鍵字 --> 狗
生成的密碼 --> dog-jdls4ksls

我看到的問題是,我看到的不是打印生成的密碼,而是:

[object Object]-jdls4ksls

我最好的猜測是,因為我使用的是 async/await,所以我打印的是 promise 內存對象而不是返回值。 但是,我不知道如何阻止以等待完成。 提供此輸出的相關代碼是從 HTML 正文調用的 render.js 的最后一行。

任何幫助,將不勝感激!

就上下文而言,我主要是一名后端開發人員,擁有豐富的 python 和 C/C++/C# 經驗。 我的目標是將 C#/.NET GUI 應用程序重新構建為電子應用程序。

這是我所有的代碼。

main.js

const {app, BrowserWindow, ipcMain} = require("electron")
const path = require("path")

function generatePassword(keyword) {
    console.log(keyword)
    return keyword + '-' + Math.random().toString(36).substring(2,12)
}

function createWindow () {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        resizable: false,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    })

    win.loadFile('html/passwordGen.html')
}

app.whenReady().then(() => {
    ipcMain.handle("generatePassword", generatePassword)
    // console.log(generatePassword('test string')) // works
    createWindow()
}).catch(error => {
    console.log(error) // log error to console
    app.quit() // quit the app
})

preload.js

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('main', {
    genPW: (keyword) => ipcRenderer.invoke("geåneratePassword", keyword)
})

渲染.js

async function testClick () {
    const pw_root = document.getElementById("keyword")
    const pw_label = document.querySelector("#password")
    pw_label.innerText = await window.main.genPW(pw_root.value)
}

密碼生成.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Password Generator</title>
    <link rel="stylesheet" href="../css/style.css">
    <script src="../render.js"></script>
</head>
<body>
    
    <h1>Password Generator</h1>
    <input type="text" id="keyword" placeholder="Please enter a keyword...">
    <button id="btn" onclick="testClick()">Generate Password</button>

    <h1 id="password"></h1>
</body>
</html>

編輯:

這是有效的代碼。 接受的解決方案有一個例外,我需要 1)在 generatePassword() 上保持 async/await 或 2)按照另一個解決方案中的建議將其轉換為 .then() 格式。

main.js

const {app, BrowserWindow, ipcMain} = require("electron")
const path = require("path")

function generatePassword(keyword) {
    console.log(keyword)
    return keyword + '-' + Math.random().toString(36).substring(2,12)
}

function createWindow () {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        resizable: false,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    })

    win.loadFile('html/passwordGen.html')
}

app.whenReady().then(() => {
    // ipcMain.handle("generatePassword", generatePassword)
    // console.log(generatePassword('stink')) // works
    ipcMain.handle('generatePassword', (_event, keyword) => {
        console.log(keyword); // Testing
        return generatePassword(keyword);
    });
    createWindow()
}).catch(error => {
    console.log(error) // log error to console
    app.quit() // quit the app
})

preload.js

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('main', {
    genPW: (keyword) => {
        return ipcRenderer.invoke("generatePassword", keyword)
    }
})

渲染.js

async function testClick () {
    const pw_root = document.getElementById("keyword")
    const pw_label = document.querySelector("#password")
    pw_label.innerText = await window.main.genPW(pw_root.value)
    // window.main.genPW(pw_root.value).then(res => {pw_label.innerText = res})
    // ^^^ works as well if async/await removed
}

我不認為你可以使用異步函數作為事件監聽器,你需要在這里使用常規(不是異步)函數。

function testClick() {
    const pw_root = document.getElementById("keyword")
    const pw_label = document.querySelector("#password")
    window.main.genPW(pw_root.value).then(res => {pw_label.innerText = res})
}

另外,您在這里有錯字: invoke("geåneratePassword")

你真的很親近。 使用 Elctron 的invoke方法是正確的方法。

在您的main.js文件中,Electron 的 IPC handle簽名包含channellistener器參數。 在您的代碼中,您調用generatePassword()函數代替listener參數。 相反,它應該是(event, ...args) 在您的特定情況下(event, keyword) 有關更多信息,請參閱ipcMain.handle(channel, listener)

此外,在您的preload.js腳本中,您需要做的就是在您的ipcRenderer.invoke方法前面添加一個return語句。

最后,不需要在testClick()函數上使用async Electron 的invoke處理所有這些。


main.js (主進程)

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;

const nodePath = require('path');

// Prevent garbage collection
let window;

function createWindow() {
    window = new electronBrowserWindow({
        x: 0,
        y: 0,
        width: 800,
        height: 600,
        resizable: false,
        show: false,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            preload: nodePath.join(__dirname, 'preload.js')
        }
    });

    window.loadFile('index.html')
        .then(() => { window.show(); });

    return window;
}

electronApp.on('ready', () => {
    window = createWindow();
});

electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        electronApp.quit();
    }
});

electronApp.on('activate', () => {
    if (electronBrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});

// ---

function generatePassword(keyword) {
    console.log(keyword)
    return keyword + '-' + Math.random().toString(36).substring(2,12)
}

electronIpcMain.handle('generatePassword', (event, keyword) => {
    console.log(keyword); // Testing
    return generatePassword(keyword);
});


preload.js (主進程)

const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;

contextBridge.exposeInMainWorld(
    'main', {
        genPW: (keyword) => {
            return ipcRenderer.invoke('generatePassword', keyword);
        }
    });

為簡單起見,我已將您的render.js腳本包含在結束</body>標記下方的<script>標記中。

index.html (渲染過程)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Emergency</title>
        <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
    </head>

    <body>
        <div>
            <label for="password">Password:</label>
            <input type="text" id="password">

            <input type="button" id="submit" value="Submit">
        </div>

        <div>
            <label for="generated-password">Generated Password:</label>
            <input type="text" id="generated-password" disabled>
        </div>
    </body>

    <script>
        document.getElementById('submit').addEventListener('click', () => {
            window.main.genPW(document.getElementById('password').value)
                .then((generatedPassword) => {
                    document.getElementById('generated-password').value = generatedPassword;
                })
        })
    </script>
</html>

嘗試在等待中使用雙重等待await (await callToBackend)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM