一个项目在 IOS 8.x 发现无法运行,排查之后发现是 Promise 的锅,整个项目 ES6 的语法已经使用 @Babel 转过了,但是 API 这部分没有做 Polyfill,也尽可能绕过去。

Promise 是不可避免要使用的 API,因为不想再走以前的回调的老路,因此想当然的做了一个 Polyfill,使用的就是 https://github.com/stefanpenner/es6-promise

后面发现 polyfill 不起作用,仍旧报错。

在排查过程中发现,在 IOS 8.x 系统中,如果打印 typeof Promise 会提示是一个 function,并且打印 Promise.thenPromise.catch 都是存在的方法。

而MDN上显示是可以在 IOS8.x safari 上使用的:

TIM截图20180906010532.jpg

而在 can I use 上有明确是要从 IOS 10 开始才可以(实际上从 9 好像就原生支持了)

TIM截图20180906011139.jpg

而看到一篇文章那个简单说了一下原因(https://www.jianshu.com/p/adcb6c000209):

IOS 8.1 JavaScriptCore 执行代码遇到了代码不执行的错误。
Event loop not supported

原来这个版本的jscore中正确实现了Promise的所有的API,但是底层对Event Loop是不支持的。所以Promise的特性检测能通过,但是还是报错,不能执行。

解决方案是,判断如果系统版本是ios8.1 ,强制使Promise对象为undefined,然后使用polyfill解决。

具体的原因目前没有去验证,但是我们在验证 setTimeout 的时候,也导致出现了问题,应该也是底层的 event loop 的原因(时间原因,没有去可以复现查看)

因为 IOS 8 实现了 Promise 的 API,这导致平常的 polyfill 先判断是否存在然后挂载 API 的方式是失败的,因此有两种方法去实现,一种是直接重命名使用的 Promise名称,比如使用 Promise2,另外一种是根据系统版本去挂载,如果判断是 < IOS10 的系统,则直接将 Promise = undefined,然后挂载新的 promise

import Promise2 from 'Promise2'
if(isIOS8 || isiOS9){
    Promise = undefined;
    Promise = Promise2;
}