【转载】js解决同步获取异步方法返回值问题

本文详细探讨了JavaScript中获取异步函数返回值的多种方法,从最初的错误尝试到使用回调函数,再到promise、generator和async/await等高级技术,逐步展示了异步编程的发展历程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这一篇写得太全面了,博主没有脚本*家的账号所以算是未经允许就转载了吧。但是写的好,很想留作参考
原帖连接https://www.jb51.net/article/100661.htm

怎么拿到JavaScript异步函数的返回值?

1.错误尝试

当年未入行时,我的最初尝试:(ps:嘿嘿 原博主写的)

<script>
function getSomething() {
 var r = 0;
 setTimeout(function() {
 r = 2;
 }, 10);
 return r;
}

function compute() {
 var x = getSomething();
 alert(x * 2);
}
compute();
</script>

2.回调函数

弹出的不是4,而是0,后来知道这是异步的问题,

要用回调技术来做:

<script>
function getSomething(cb) {
 var r = 0;
 setTimeout(function() {
 r = 2;
 cb(r);
 }, 10);
}

function compute(x) {
 alert(x * 2);
}
getSomething(compute);
</script>

3.promise

回调函数真是个好东西,然后一直这么写代码写了很久。遇到异步就传函数!!后来我知道有promise这一个东西,专门解决由于回调函数引起的问题,又学会了promise:

<script>
function getSomething() {
 var r = 0;
 return new Promise(function(resolve) {
 setTimeout(function() {
  r = 2;
  resolve(r);
 }, 10);
 });
}

function compute(x) {
 alert(x * 2);
}
getSomething().then(compute);
</script>

promise仍然没有放弃回调,只是回调的位置发生了改变。

4.generator

再后来我又学会了generator,知道其有中断函数执行的能力,又做了新的尝试:

<script>
function getSomething() {
 var r = 0;
 setTimeout(function() {
 r = 2;
 it.next(r);
 }, 10);
}

function *compute(it) {
 var x = yield getSomething();
 alert(x * 2);
}
var it = compute();
it.next();
</script>

同步的写法,能实现异步的逻辑,感觉高大上了很多。

5.promise + generator

后来又听说promise加generator,才是异步的完美方式,赶紧用高射炮打蚊子(这个例子,还不足以说出二者在一起用的好处):

<script>
function getSomething() {
 var r = 0;
 return new Promise(function(resolve) {
 setTimeout(function() {
  r = 2;
  resolve(r);
 }, 10);
 });
}

function *compute() {
 var x = yield getSomething();
 alert(x * 2);
}
var it = compute();
it.next().value.then(function(value) {
 it.next(value);
});
</script>

6.async

心想这算是够屌的吧,后来又听说es7给出了终极方案:async。

作为爱学习的少年,心想自己不能被落下:(ps:都是爱学习的少年呦)

<script>
function getSomething() {
 var r = 0;
 return new Promise(function(resolve) {
 setTimeout(function() {
  r = 2;
  resolve(r);
 }, 10);
 });
}

async function compute() {
 var x = await getSomething();
 alert(x * 2);
}
compute();
</script>
到这里终于长出了一口气。(ps:呼~~~~~)
<think>好的,我现在需要解决用户的问题:如何使用Python的ExecJS获取异步JavaScript函数的返回值。用户之前可能已经了解过ExecJS的基本用法,现在遇到了异步函数返回的问题。根据提供的引用,用户知道直接调用async函数会返回Promise对象,而无法直接获取结果,并且不想在数据中另建字段保存结果。 首先,我需要回忆ExecJS库的功能。ExecJS允许Python执行JavaScript代码,但通常是同步的。而异步函数如setTimeout或fetch在JS中会返回Promise,ExecJS默认可能不支持等待这些异步操作完成。 接下来,思考可能的解决方案。根据引用2中提到的问题,async函数返回的是Promise,所以需要让ExecJS环境能够等待Promise解析。可能需要修改JS代码,使用同步的方式执行异步操作,或者在ExecJS的环境中模拟事件循环。 然后,考虑是否有库或方法可以支持。例如,在Node.js中可以使用deasync等库将异步转为同步,但ExecJS可能运行在不同的JS环境中,如PhantomJS或Node。需要确认ExecJS使用的运行时环境是否支持同步执行异步代码。 另外,可能需要通过回调函数或者Promise链来获取结果。例如,在JS代码中,将异步操作的结果通过回调传递给Python端,或者使用IIFE(立即调用函数表达式)来等待Promise并返回结果。 然后,验证这些方法的可行性。比如,在ExecJS中执行一个包含async/await的IIFE,可能需要在JS代码中正确处理Promise,并确保执行环境支持ES6语法。例如: ```javascript async function demo() { return await someAsyncFunction(); } demo(); ``` 但这样可能仍然返回Promise对象。因此,需要修改为同步执行,或者使用类似eval的方式强制等待结果。 另一个方法是使用回调函数。例如,在JS中定义回调,将结果作为参数传递,并在Python中捕获这个回调的输出。但ExecJS可能不支持这种方式,因为它是同步执行的。 或者,可以考虑使用Node.js的child_process或者其它更强大的库如PyV8,但用户明确要求使用ExecJS,因此需要在该库的限制下找到解决方案。 可能最终的解决方案是在JS代码中使用同步风格的异步操作,例如使用deasync库,或者在JS环境中实现事件循环,让ExecJS能够等待Promise解决。例如: ```javascript const deasync = require('deasync'); function syncDemo() { let done = false; let result; someAsyncFunction().then(res => { result = res; done = true; }); deasync.loopWhile(() => !done); return result; } syncDemo(); ``` 但需要确保ExecJS的环境安装了deasync,并且支持require。这可能需要在Node环境下运行ExecJS,并且正确配置。 然后,考虑如何在Python中调用这个同步化的函数。例如,通过ExecJS编译并调用syncDemo函数,这样就能返回结果。 另外,用户可能遇到的另一个问题是环境配置。例如,ExecJS默认可能使用系统安装的JavaScript引擎,如Node.js,需要确保Node环境可用,并且相关模块已安装。 最后,总结步骤:在JS代码中将异步函数转换为同步执行,使用deasync或其他方法,然后在Python中调用该同步函数获取结果。同时,需要注意ExecJS的环境配置和依赖安装。</think>要使用Python的ExecJS获取异步JavaScript函数的返回值,需要通过JavaScript环境实现同步化操作。以下是具体步骤和示例: ### 解决方案步骤 1. **配置Node.js环境** 确保系统已安装Node.js,ExecJS默认使用Node.js作为执行环境[^1]。 2. **安装依赖库** 在Node.js环境中安装`deasync`库,用于将异步操作转为同步: ```bash npm install deasync ``` 3. **编写同步化JavaScript代码** 在异步函数外包裹同步逻辑,通过`deasync`阻塞事件循环直到结果返回: ```javascript const deasync = require('deasync'); function asyncDemoSync() { let done = false; let result; // 示例异步函数(如setTimeout模拟) new Promise(resolve => { setTimeout(() => resolve("异步结果"), 1000); }).then(res => { result = res; done = true; }); // 阻塞直到异步操作完成 while (!done) { deasync.sleep(100); } return result; } ``` 4. **Python调用同步化函数** 通过ExecJS调用处理后的同步函数: ```python import execjs # 读取JS文件 with open('async_demo.js', 'r') as f: js_code = f.read() ctx = execjs.compile(js_code) result = ctx.call('asyncDemoSync') print(result) # 输出:异步结果 ``` ### 关键点说明 - **同步化原理**:`deasync`通过轮询机制阻塞代码执行,直到异步操作完成[^2]。 - **环境依赖**:需确保Node.js环境和依赖库正确安装。 - **性能注意**:同步化操作会阻塞线程,建议控制超时时间避免死循环。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值