网站搜索

在 Typescript 中尝试执行时出现 async/await 问题,但在 Javascript 中可以正常工作


我有一个客户端应用程序,它支持 JavaScript 脚本。该应用程序是用 TypeScript 编写的。虽然一切似乎运行正常,但当用户尝试在他们的脚本中使用 await 时,我遇到了问题。

我用纯JS重写了这个场景,并做了一个fiddle。在这个环境下,它按预期工作,也就是说:消息框会在用户按下按钮后一个接一个地出现。

这是 fiddle: http://jsfiddle.net/927mtdz8/42/

然而,应用程序中的 Typescript 代码在运行脚本时,所有消息框似乎会同时弹出,看起来像是忽略了 await。

我无法弄清楚哪里出了问题。这是简化后的 TS 代码:

function makeScript(owner:string, text: string, argsSig: string) {

    let _scriptFunc_: any;
    let own = owner;
        try {
        const promiseCode = `let __res = null;let __rej = null;let __promise = new Promise((resolve, reject) => {__res = resolve;__rej = reject;});try {\n`;
        const ending = `;\n;__res();} catch (err) { __rej(err);}; return __promise;`;
        const scriptSource = "_scriptFunc_ = async function(" + argsSig + ") {\"use strict\";\n" + promiseCode + text + ending + "\n}";
        eval(scriptSource);
    }
    catch (err) {
        console.log(err);
        return null;
    }

    const ret = _scriptFunc_.bind(this);
    return ret;
}

async function messagebox(_text: string):Promise<string> {
    let resolveFunc:Function = null;
    let rejectFunc:Function = null;
    let promise = new Promise<string>((resolve,reject) => {
        resolveFunc = resolve;
        rejectFunc = reject;
    });
    let win = document.createElement("div");
    let $win = $(win);
    document.body.appendChild(win);
     win.innerHTML = `
        <div id="messageboxtext"></div>
        <button id="accept" style="width:200px;height:50px;">OK</button>
    `;
    const acceptButton = $("#accept", $win);
    const $text = $("#messageboxtext", $win);
    $text.text(_text);
    $(acceptButton).click(() => {
            resolveFunc("ok");
        $win.remove();
    });
    $win.css({'position':'relative','width':'auto', 'height':'auto', 'background-color':'red'});
    return promise
}

class Messagebox {
    public static async ShowInput(_text: string): any {
        return await messagebox(_text);
    }
}

class ScriptBuilder {
    public scriptThis:any;
    public makeScript(owner:string, text: string, argsSig: string): any {
        try {
            const scr = makeScript.call(this.scriptThis, owner, text, argsSig);
            return async (...args: any[]) => {
                try {
                    let ret = await scr(...args);
                    return ret;
                } catch (err) {
                    console.log(err);
                }
            };
        } catch (err2) {
            console.log(err2);
        }
    }
}

let scrBuilder = new ScriptBuilder();
scrBuilder.scriptThis = {Message:""};
(<any>window).Messagebox = Messagebox;
let _script = scrBuilder.makeScript("scriptName", `
  this.Message += await Messagebox.ShowInput(question + ' 1 ');
  console.log(this.Message);
  this.Message += await Messagebox.ShowInput(question + ' 2 ');
  console.log(this.Message);
  this.Message += await Messagebox.ShowInput(question + ' 3 ');
  console.log(this.Message);
`, "question");
_script("Please press the button");

不幸的是,这段 TS 代码在 JSFiddle 中无法编译,导致转译后的代码出错,所以我无法创建一个它的 fiddle。

基本上,看起来当脚本函数执行时,它的整个主体会一次性运行,就好像里面没有任何 await 一样。

有人知道为什么 await 似乎没有被遵守吗?

Typescript 版本 3.9.7,这是 tsconfig:

{
    "compilerOptions": {
        "sourceMap": true,
        "outDir": "./build",
        "noImplicitAny": true,
        "esModuleInterop": true,
        "noImplicitReturns": true,
        "target": "es5",
        "downlevelIteration": true,
        "lib": [
            "DOM",
            "ES6",
            "DOM.Iterable",
            "ScriptHost"
        ],
        "types": [
            "jquery"
        ]
    },
    "exclude": [
        "node_modules"
    ],
    "include": [
        "./src/ts/*"
    ]
}

编辑:似乎是我的环境出了问题,因为它在 StackBlitz 应用中可以正常工作:https://stackblitz.com/edit/typescript-ldr5sm

编辑2:我试着更新注入的 Promise 代码以使脚本异步,但即使像这样的代码也会做同样的事情(不遵守 await):

async ƒ (match, line) {
   let p = new Promise((resolve, reject) => {
       (async () => {
         try {
            await Messagebox.ShowInput("...");
            await Messagebox.ShowInput("...");
            resolve('')
         } catch (err) {
           reject(err)
         }
       })()
   });
   return p;
}

两个消息框同时弹出。

答案#1

抱歉进行灵异狩猎。错误出在客户端使用上。

客户做了这个:

this.something = await Messagebox.Show("...").toString();

它不是在等待一个函数,而是在等待一个 toString(),这是同步的。奇怪的是,JavaScript 对这种语法没有报错,我花了很多时间才弄明白,因为我手头没有用户在脚本中尝试的确切代码。