惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
Intezer
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
AWS News Blog
AWS News Blog
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Cybersecurity and Infrastructure Security Agency CISA
N
News | PayPal Newsroom
T
Tenable Blog
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Secure Thoughts
P
Privacy International News Feed
IT之家
IT之家
Project Zero
Project Zero
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
博客园_首页
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
NISL@THU
NISL@THU
I
InfoQ
D
DataBreaches.Net
有赞技术团队
有赞技术团队
K
Kaspersky official blog
Security Latest
Security Latest
The Register - Security
The Register - Security
Hugging Face - Blog
Hugging Face - Blog
S
Security @ Cisco Blogs
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
H
Hackread – Cybersecurity News, Data Breaches, AI and More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
AI
AI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
Security Archives - TechRepublic
Security Archives - TechRepublic
N
News and Events Feed by Topic

Quip Blog

Making the Quip editor accessible Paying down our accessibility debt Announcing the 2021 Diversity Scholarship Winners Quip is Back and Better Than Ever A New Developer Experience for our Live Apps Community Announcing the 2021 Quip Diversity Scholarship 3 Ways Salesforce Anywhere Helps Sales Ops Make Their Stakeholders Successful How Cytiva Transformed Account Planning with Salesforce Anywhere Quip and Salesforce Anywhere Customer Support Documentation Has a New Home
Solving Performance Issues with a Multi-Frame Application
By Chris de la Iglesia · 2020-12-15 · via Quip Blog

The Problem to Solve

Salesforce Anywhere is a new communication app, built by Quip, to provide a place for communication and collaboration inside of Salesforce. As part of this new product, we planned to build new chat features into the Salesforce Lightning experience itself. Since Salesforce Anywhere runs on the Quip backend and tech stack, which is separate from the Salesforce tech stack, this required some special design decisions on our part.

Initially, we built a new React app to run Salesforce Anywhere that would re-use client-side code from Quip and connect to the Quip backend. Our first version ran an instance of this app in each chat window inside of an iframe, which communicated using messages with the main Salesforce app to create new chat windows or open up links.

This caused a few technical issues. First of all, it used up a lot of memory. When opening up a page with the chat header and five chat windows, the Salesforce Anywhere app consumed upwards of 500MB of Javascript VM memory alone. While our powerful development machines could easily handle that amount, many of our customers would have trouble if running other intensive applications.

In addition, loading up a full React app plus copies of our data management and other duplicate code takes time. In our initial version, it took roughly two to three seconds to open up a new chat, which is borderline unusable from a productivity perspective. We would need to get that load time down below a second, hopefully below half a second, before we could ship.

The Solution: A Multi-Frame Application

To solve these problems, we decided to rearchitect our app to use one instance of our React app that controlled each of the iframes on the page. Since React can easily render in multiple places, one app could be loaded that would render into each iframe every time a new chat window was opened. This would also solve the data duplication issue, as the same data management could be used for each application.

Normally, cross-frame functionality can only be done using messages sent back and forth between the different sets of Javascript code. However, if every frame comes from the same origin, then even if the app is embedded inside another webpage, each frame can directly access the Javascript memory of every other frame of the same origin. This allowed our code to run basically as-is, only using different window objects.

We chose to use the chat header (shown below) to be the controller frame that would render each other frame (called view frames). This is because the chat header is loaded up when Salesforce Lightning first loads, and so is always reliably loaded. Upon loading of the main Salesforce app, Salesforce Anywhere loads into a hidden iframe normally with no multi-frame shenanigans involved.

When a chat window opens up, it loads a minimal bundle of Javascript and CSS that only handles initialization. Upon loading, this “view frame” sends a message to the controller frame (i.e. the chat header), telling it which frame it is from and to start rendering. The controller frame then renders the React app into the view frame.

This change required a significant amount of refactoring to certain parts of our codebase, as some parts were built with only a single frame in mind. Thankfully, we already had some support code for multiple frames for our desktop app, since certain popovers and modals run in separate frames for a desktop-like experience. This code would allow us to create and manage window-scoped objects for each frame (such as our focus stack, which manages the focus inside each window). Every part of our codebase would need to be frame-agnostic, so we were able to use this support code to separate the logic of the code from the frame that it was operating on.

One unique point is the cross-frame messages sent from Salesforce Anywhere to the main Salesforce app. In our initial app, each frame individually sent messages to communicate with Salesforce. This meant that, from the Salesforce side, messages came from every frame and not just the single controller frame. We wanted to maintain this interface between Anywhere and Salesforce, as it is simpler and easier to understand, but in the new multi-frame world all of the view frames only had a small amount of code to send an initialization message to the controller frame. Thankfully, we had already encapsulated the message sending/receiving handlers inside a convenient bridge object. Each view frame would create its own bridge object that would send messages originating from the view frame but could be used from the controller frame. When the controller frame needed to send a message for a view frame, it would find the corresponding bridge object and send the message using that.

The Result

After implementing this system, we saw large improvements to memory usage and chat window load times. Each chat window went from taking up 40MB of memory per window to <10MB of memory per window, dramatically lowering overall memory usage when users have many windows opened. In addition, load times for each chat window decreased from three seconds to less than a second, improving usability and enjoyability.

As part of this investigation, several lessons became clear. First, measuring exactly what you want to improve is very important. We did a large amount of profiling and investigation to determine what was using up memory and why load times were so bad, which allowed us to proceed with confidence and get the results that we wanted. Second, building a complete but inefficient version of your app first can provide tons of valuable information on what will end up using the most resources in the final product.