在 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 对这种语法没有报错,我花了很多时间才弄明白,因为我手头没有用户在脚本中尝试的确切代码。
