KKJSBridge icon indicating copy to clipboard operation
KKJSBridge copied to clipboard

ajax async:false同步请求

Open dhui68 opened this issue 3 years ago • 11 comments

ajax async:false同步请求不生效,不会等success回调后再执行下面代码,

我尝试修复,使用window.prompt("SyncCall",obj),但是发现iOS14不行,iOS14以下正常了。

请问有什么好的方案解决同步问题吗?

dhui68 avatar Oct 30 '20 03:10 dhui68

嗯,你用的是 pod 'KKJSBridge/AjaxHook' 是这个版本吗? 这个版本是统一都当做异步来处理的。

我觉得你还是通过 await 来解决吧。

karosLi avatar Nov 05 '20 04:11 karosLi

同求同步解决方案。调试了很久才发现不支持async:false。前端有很多地方使用了async:false,不能要求他们都改成await。🤦‍♀️

erickyim avatar Nov 19 '20 12:11 erickyim

同求同步解决方案。调试了很久才发现不支持async:false。前端有很多地方使用了async:false,不能要求他们都改成await。🤦‍♀️

你用的是哪种 ajax hook 方案?


# 分别提供了 ajax hook 和 ajax urlprotocol hook 两种方案,可以根据具体需求自由选择。
# 只能选择其中一个方案,默认是 ajax protocol hook。
pod 'KKJSBridge/AjaxProtocolHook'
pod 'KKJSBridge/AjaxHook'

karosLi avatar Nov 20 '20 03:11 karosLi

pod 'KKJSBridge/AjaxProtocolHook', '1.3.2' pod 'KKJSBridge/AjaxHook', '1.3.2'

ajax hook 和 ajax urlprotocol hook 方案都支持如下特性:

2020.11.21 (1.3.2)

  • 支持 JSBridge 同步调用
  • 支持纯文本的 ajax 同步请求(还不支持 Blob 和 表单)
  • 支持通过 document.cookie 同步从 NSHTTPCookieStorage 读取最新的 Cookie

已经支持 ajax 同步调用了,目前只支持纯文本的同步调用,还不支持表单的同步调用,不过一般情况下也够用了。

karosLi avatar Nov 20 '20 16:11 karosLi

@wjiuxing

karosLi avatar Nov 20 '20 16:11 karosLi

Sorry,这几天在老家,只能用手机粗略的看一下。

先把我的经验分享给大家。

以window.prompt 方法同步实属无奈之举,有几点需要注意:

  1. prompt 回调方法的 completionHandler,必须且仅需调用一次,不调或者多调都会 crash;

  2. completionHandler 要尽早调用,如果是仅需在native侧就能完成的 JS- Native交互,小心一点那还能处理;

  3. 如果同步Ajax用此方式,native代发同步网络请求是不现实的,发异步请求又会遇见进程间通信超时(会有一条log, [IPC] Connection::waitForSyncReply: Timed-out while waitting for reply...),大概10秒钟左右是冻屏状态。

我在我的fork里做了同步交互的支持(对于没有返回值的同步交互,也尽早消费了 completionHandler,详见 commit https://github.com/wjiuxing/KKJSBridge/commit/d867a85464765da1582a2dd7c4a5b6d8349c8f0e )但是同步 Ajax 还是让 H5 部门修改的。

另外,@KarosLi 我在手机浏览代码时有几个小小的想法:

  1. 如果必须有的功能,是不是可以考虑放主类里,分类和 associated object 都会影响性能;

  2. commit 尽量保持原子性,不提交和本次无关的代码,也可能是我手机看的粗略而没有理解到位 🙏

最后,感谢 @KarosLi 做出的贡献,为我们提供这样一个得心应手的工具,也感谢 @KarosLi 费心竭力为我们解决问题。Thx 🙏

发自Jiuxing Wang's iPhone

在 2020年11月21日,上午12:21,Karosli [email protected] 写道:



@wjiuxinghttps://github.com/wjiuxing

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/karosLi/KKJSBridge/issues/43#issuecomment-731265554, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AA73W2B6YWEZZL6OX3WB3XDSQ2JRHANCNFSM4TEQLL6A.

嗯,感谢你的认真和建议。 这里是出于大家对 ajax sync 同步请求的诉求,所以提供了一个同步方式。不过总体上而言,能让 H5 改的,就尽量让 H5 改,尽量使用 await 或者 使用 ajax async。

1、prompt 回调方法的 completionHandler,目前处理也是只回调一次的。

2、completionHandler 目前的处理要尽早调用,对于没有返回值的同步交互,也尽早消费了 completionHandler。

3、如果同步Ajax用此方式,native代发同步网络请求是不现实的,发异步请求又会遇见进程间通信超时(会有一条log, [IPC] Connection::waitForSyncReply: Timed-out while waitting for reply...),大概10秒钟左右是冻屏状态。 你说的这个情况我相信应该是有的,不过目前我还没测试的那么充分。不过总体上而言,能让 H5 改的,就尽量让 H5 改。

4、之所以放到分类,是考虑到别人不一定会使用 KKWebView,而是自定义的 WKWebView,那分类的话自定义 WKWebView 可以方便集成 JSBridge 同步调用的能力。

5、commit 确实应该要原子提交,这点做得不太好。哈哈,我是有时候考虑的太多,就会把所有地方都改了,有点强迫症。下次你用电脑看吧,然后有问题我们在互相交流。

wjiuxing avatar Nov 21 '20 01:11 wjiuxing

另外关于 associated,底层实际上还是一个 hash map,对象指针作为 key,时间复杂度是 O(1),性能是上还可以的,只是内存会增加一点。

void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    j->second = ObjcAssociation(policy, new_value);
                } else {
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                }
            } else {
                // create the new association (first time).
                ObjectAssociationMap *refs = new ObjectAssociationMap;
                associations[disguised_object] = refs;
                (*refs)[key] = ObjcAssociation(policy, new_value);
                object->setHasAssociatedObjects();
            }
        } else {
            // setting the association to nil breaks the association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i !=  associations.end()) {
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    refs->erase(j);
                }
            }
        }
    }
    // release the old value (outside of the lock).
    if (old_association.hasValue()) ReleaseValue()(old_association);
}

karosLi avatar Nov 21 '20 02:11 karosLi

是的,问题在dealloc的时候会有一些影响。

发自Jiuxing Wang's iPhone

在 2020年11月21日,上午10:42,Karosli [email protected] 写道:



另外关于 associated,底层实际上还是一个 hash map,对象指针作为 key,时间复杂度是 O(1),性能是上还可以的,只是内存会增加一点。

void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) { // retain the new value (if any) outside the lock. ObjcAssociation old_association(0, nil); id new_value = value ? acquireValue(value, policy) : nil; { AssociationsManager manager; AssociationsHashMap &associations(manager.associations()); disguised_ptr_t disguised_object = DISGUISE(object); if (new_value) { // break any existing association. AssociationsHashMap::iterator i = associations.find(disguised_object); if (i != associations.end()) { // secondary table exists ObjectAssociationMap *refs = i->second; ObjectAssociationMap::iterator j = refs->find(key); if (j != refs->end()) { old_association = j->second; j->second = ObjcAssociation(policy, new_value); } else { (*refs)[key] = ObjcAssociation(policy, new_value); } } else { // create the new association (first time). ObjectAssociationMap *refs = new ObjectAssociationMap; associations[disguised_object] = refs; (*refs)[key] = ObjcAssociation(policy, new_value); object->setHasAssociatedObjects(); } } else { // setting the association to nil breaks the association. AssociationsHashMap::iterator i = associations.find(disguised_object); if (i != associations.end()) { ObjectAssociationMap *refs = i->second; ObjectAssociationMap::iterator j = refs->find(key); if (j != refs->end()) { old_association = j->second; refs->erase(j); } } } } // release the old value (outside of the lock). if (old_association.hasValue()) ReleaseValue()(old_association); }

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/karosLi/KKJSBridge/issues/43#issuecomment-731495064, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AA73W2ETSJQ4Q4KK2RZQUW3SQ4SI5ANCNFSM4TEQLL6A.

wjiuxing avatar Nov 21 '20 03:11 wjiuxing

同求同步解决方案。调试了很久才发现不支持async:false。前端有很多地方使用了async:false,不能要求他们都改成await。🤦‍♀️

你用的是哪种 ajax hook 方案?


# 分别提供了 ajax hook 和 ajax urlprotocol hook 两种方案,可以根据具体需求自由选择。
# 只能选择其中一个方案,默认是 ajax protocol hook。
pod 'KKJSBridge/AjaxProtocolHook'
pod 'KKJSBridge/AjaxHook'

用的 pod 'KKJSBridge/AjaxProtocolHook', jQuery代码如下:

$.ajax({
    type: "POST",
    async: false,
    headers: {
        "Content-Type": 'application/x-www-form-urlencoded;charset=utf-8'
    },
    url: "/home/page",
    data: {
        from: "home"
    },
    success: function (data) {
        console.log(111);
        alert("success: \n" + data);
    },
    error: function (error) {
        console.log("error");
        alert("error: \n" + data);
    }
});

erickyim avatar Nov 23 '20 03:11 erickyim

pod 'KKJSBridge/AjaxProtocolHook', '1.3.4'

@erickyim 试下这个版本

karosLi avatar Nov 23 '20 04:11 karosLi

pod 'KKJSBridge/AjaxProtocolHook', '1.3.4'

@erickyim 试下这个版本

已经可以了,非常感谢~

erickyim avatar Nov 23 '20 06:11 erickyim