【拓展】异步与同步:从jsx获取内容到js

[sc name="zhuanzai" author="Barranca" link="https://www.davidebarranca.com/2014/12/html-panels-tips-15-asynchronous-vs-synchronous-evalscript/" ][/sc]

引用StackOverflow

当您同步执行某事时,您会等待它完成,然后再继续执行另一个任务。当您异步执行某件事时,您可以在它完成之前继续执行另一个任务。

或者视觉上:

【拓展】异步与同步:从jsx获取内容到js
【拓展】异步与同步:从jsx获取内容到js

早期evalScript是同步的,现在则是异步的:

CSXSInterface.instance.evalScript('jsxFunction'); // Sync 同步
csInterface().evalScript('jsxFunction'); // Async 异步

异步示例

evalScript 函数需要两个参数:

  • 要运行的 ExtendScript 代码。
  • 一个回调函数,它反过来将来自 ExtendScript 调用的返回值作为参数。

默认行为如下:

var csInterface = new CSInterface();
var username = undefined;

// AE 脚本中 获取当前系统用户名
csInterface.evalScript('system.userName', function(result) {
  username = result;
});

alert(username); // undefined

在上面的例子中,system.userName执行后会直接返回——当前在 AE中的数据被传递给回调,回调将其分配给变量username。由于evalScript的异步性质,最后一句显示“未定义” :第 6 行还未执行完毕,解释器就会继续执行到第 9 行而不等待 ExtendScript 返回(4~7行),因此username 仍然是undefined

就如同:你让你老婆出去买东西,然后她前脚刚出门,你就打开冰箱说“老婆!你买的东西呢!”

同步解决方法

有几种不同的方法可以模拟同步行为

1.设置超时

最简单的方法:等你老婆从商店回来:

var csInterface = new CSInterface();
var username = undefined;

csInterface.evalScript('system.userName', function (result) {
  username = result;
});
setTimeout(alert(username), 500);  // 延迟500ms再弹窗

这并不理想。因为不知道要等待多长时间  –  这取决于要执行的 ExtendScript 代码。

2. 在回调中嵌套代码

如果alert在回调中使用,则它可以正常工作:

var csInterface = new CSInterface();
var username = undefined;

csInterface.evalScript('system.userName', function (result) {
  username = result;
  alert(username);
});

当然,这会导致所谓的回调地狱 ——将 evalScript 调用嵌套在另一个调用中,例如:

csInterface.evalScript('/* 你的代码1 */', function(result) {
  csInterface.evalScript('/* 你的代码2 */', function (result) {
    // 等等
  })
});

如果你没有特别的需求,它也能凑合用。

3. 事件驱动回调

从 CEP 5.2 开始支持此方法。可以通过PlugPlugExternalObject实现自定义事件,这些事件由 ExtendScript 调度并从 JS 侦听。

先把 ExtendScript 代码放在 JSX 文件中:

// in jsx file
function get_username() {
    // 调用lib
    try {
        var xLib = new ExternalObject("lib:PlugPlugExternalObject");  // 老版本用lib://  ?待验证
    } catch (e) {
        return false;
    }

    var eventObj = new CSXSEvent(); // 创建事件对象
    eventObj.type = "my_event";     // 创建事件类型,用于外部验证
    eventObj.data = system.userName;// 输入事件数据
    eventObj.dispatch();            // 发送事件
    xLib.unload();                  // 注销lib?
    return true;
}

然后在 JS 中设置监听器,用于监听数据的接受;

var csInterface = new CSInterface();
// 监听
csInterface.addEventListener("my_event", function (event) {
    alert(event.data);  // 返回接受的数据
});

// 判断是否正常执行lib
csInterface.evalScript("get_username()", function (result) {
    if (result == false) {
        alert("There's been a problem.");
    }
});

请注意,正如Kris Coppieters等其他开发人员所假设的那样,“即使您设法从 JS 的不同部分进行多个 JSX 调用,也可能无法同时运行多个 ExtendScript ”。

其他说明

(1)如果3的事件是绑定在单击事件上的,你需要先侦听获取事件,再处理完事件后,注销。否则每次单击都会只addListen,多次执行

function test() {
    var csInterface = new CSInterface();

    function get_data(event) {
        alert(event.data);
        csInterface.removeEventListener("my_event", get_data);
    }
    csInterface.addEventListener("my_event", get_data);

    csInterface.evalScript("get_username()", function (result) {
        if (result == false) {
            alert("未成功加载lib");
        }
    });
}

(2)JSX传回js的类型为字符串,所以想传对象回来,需要先在JSX里return JSON.stringify(你的对象),然后在js里 JSON.parse(返回值)

给TA充电
共{{data.count}}人
人已充电
AE开发脚本开发

【脚本案例】关键帧时间复刻

2021-10-4 2:05:13

AEAE开发AE插件/脚本脚本开发

【AE脚本】以播放头前一个关键帧的速度添加关键帧 | 熊猫 | 免费

2021-10-10 13:58:06

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
搜索