Slow JavaScript execution inside Expo GO on a device

Hi all,

I’m using a pure JavaScript library to do some “heavy” processing, in this case jpeg-asm to do some JPEG decoding.

For a particular image, decoding takes:

  • Web (in Chrome on Mac): ~1.5 seconds
  • Web (in Chrome/Safari on iPhone XS): ~1.3 seconds
  • Snack in Expo GO on iPhone simulator (on Mac): ~1.5 seconds
  • Snack in Expo GO on iPhone XS device: 25 seconds
  • Snack in Expo GO on Samsung Galaxy S9 device: 20 seconds

What could be the reason that running this JavaScript code on a device is so much slower than in a web browser for example?

I was told that the Expo JavaScript module runs inside JavaScriptCore on a VM on the device, inside the Expo GO app. Could it be that the resources (CPU/memory) assigned to this VM are much smaller than the JavaScript processor of a web browser or of the iPhone Simulator? Is there any way to change this?

Do you know any other ways to improve the performance (without touching the code)?

I have not yet tried to publish my app to either Play Store or App Store. Would you think this would improve the performance, or is the JavaScript execution similar to running inside Expo GO?

Any help or insight is appreciated. Thanks in advance!

Kind regards,
Sander

Expo CLI 4.3.5 environment info:
System:
OS: macOS 10.15.7
Shell: 5.0.16 - /usr/local/bin/bash
Binaries:
Node: 12.16.2 - /usr/local/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 6.14.9 - /usr/local/bin/npm
Managers:
CocoaPods: 1.9.1 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 14.1, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0
IDEs:
Android Studio: 4.0 AI-193.6911.18.40.6514223
Xcode: 12.1/12A7403 - /usr/bin/xcodebuild
npmPackages:
expo: ~40.0.0 => 40.0.1
react: 16.13.1 => 16.13.1
react-dom: 16.13.1 => 16.13.1
react-native: https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz => 0.63.2
react-native-web: ~0.13.12 => 0.13.18
npmGlobalPackages:
expo-cli: 4.3.5
Expo Workflow: managed

JSC(distributed with react-native) on android has JIT (Just-in-time compilation) disabled (depending on version partially or fully) to limit binary size, in most cases it does not affect performance, but in yours, it probably would have an impact. For iOS JSC is distributed with a system and I’m not sure with what options JSC is compiled there.

  • Web (outside Expo): ~1.5 seconds

Did you test that on mobile device? If not try it. If on mobile device browser you are also getting around 20 seconds, that most likely means that there is nothing you can do to improve that

I was told that the Expo JavaScript module runs inside JavaScriptCore on a VM on the device, inside the Expo GO app. Could it be that the resources (CPU/memory) assigned to this VM are much smaller than the JavaScript processor of a web browser or of the iPhone Simulator? Is there any way to change this?

JSC is not a VM in the same way as you can create VM with a different operating system. It’s sth like e.g Java Virtual Machine just for JS. Basically, JSC is a library, that “takes javascript as an argument” and executes it. So memory allocation and cpu limits will be the same as for any app, only potential difference can be that builtin browser can have some special rules/priority for resources

Do you know any other ways to improve the performance (without touching the code)?

  • Try building production js bundle and test in on Expo Go (or just build standalone app, for iOS you will need to submit it to appstore). It might help a bit but it won’t be order of magnitude improvment
  • If you are considering ejecting
    • you can try switching to a different version of jsc, but I don’t think there is a version with JIT fully enabled, so for max gains, you would need to compile your own version which is not a simple process
    • you can try using hermes instead of jsc, technically hermes does not have JIT either it’s possible that it might be faster
    • use native implementation

First of all, thanks a lot for your informative reply! I really appreciate it.

Good question. This was on the Macbook indeed. But if I test it on the device (iPhone XS), I get similar results. It’s even a bit quicker. So it’s not the device capacity itself…

  • Web (outside Expo, on Mac): ~1.5 seconds
  • Web (outside Expo, on iPhone XS): ~1.0 seconds (both Safari and Chrome)

Would it help if I would prepare a Snack (and HTML) to isolate the problem? That wouldn’t cost too much effort.

I attached links to a Snack and an example web page containing the same JavaScript code in my original post.
The duration of decoding (only) will be shown below the image.
(Loading of the Snack can take about 1 minute, while displaying the Expo logo.)

By that you mean with expo publish? (Or locally via expo start --no-dev --minify?)

I did both and there is not much difference in performance.

  • expo start (26 sec)
  • expo start --no-dev --minify (22 sec)

A little update:

I have managed to run the code inside a <WebView> component, including communication to/from React Native. Here the performance is quick, about 1.5 sec, also on the device. Not that pretty, but it will do as a workaround for the time being.

This post and this example helped me a lot.

I have made a new Snack for the WebView approach. I have some problems running the Snack, but when I run it (on simluator and device) via my local machine, it works fine.

1 Like

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.