Change:
In the renderer we want to stay away from sync fs API calls to because each call will stop the VM from doing anything. We should try to use the async fs APIs. The code in question is:
What about ?
yes, I reported those at the same time I reported this one via
There about 20 files that I need to run the checks on (this will definitely grow). Assuming there are about 20 paths in the PATH env variable, that is about 400 file checks to make in the worst case scenario If I do all of this async, thats about 400 async calls made at the same time. This can have an adverse affect as well correct? Or it doesnt matter at all?
anything is better than doing it sync, especially if you are stat'ing 400 files which probably means that the user cannot do anything for a couple of 100ms. We have  that allows to batch resolve. my 2 cents: having to stat 400 files for a feature seems wrong to me, especially if this blocks a piece of UI from working properly. At the very minimum this should run in the background, maybe buffered and not block any UI from showing up.

Discussion:
}; extensionTips: { [id: string]: string; }; extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; <del> exeBasedExtensionTips: { [id: string]: string; }; </del> <ins> exeBasedExtensionTips: { [id: string]: any; }; </ins> extensionKeywords: { [extension: string]: string[]; }; extensionAllowedBadgeProviders: string[]; keymapExtensionTips: string[];

import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; <del> import * as fs from 'fs'; </del> <ins> import * as pfs from 'vs/base/node/pfs'; import * as os from 'os'; </ins> import { flatten, distinct } from 'vs/base/common/arrays'; interface IExtensionsContent {

this._suggestTips(); this._suggestWorkspaceRecommendations(); <ins> // Executable based recommendations carry out a lot of file stats, so run them after 10 secs // So that the startup is not affected setTimeout(() => this._suggestBasedOnExecutables(this._exeBasedRecommendations), 10000); </ins> } getWorkspaceRecommendations(): TPromise<string[]> {

const fileBased = Object.keys(this._fileBasedRecommendations) .filter(recommendation => allRecomendations.indexOf(recommendation) !== -1); <del> const exeBased = distinct(this._suggestBasedOnExecutables()); </del> <ins> const exeBased = distinct(this._exeBasedRecommendations); </ins> this.telemetryService.publicLog('extensionRecommendations:unfiltered', { fileBased, exeBased });

}); } <del> private _suggestBasedOnExecutables(): string[] { if (!process.env.PATH || this._exeBasedRecommendations.length > 0) { return this._exeBasedRecommendations; } let envpaths = process.env.PATH.split(process.platform === 'win32' ? ';' : ':'); </del> <ins> private _suggestBasedOnExecutables(recommendations: string[]): void { const homeDir = os.homedir(); </ins> let foundExecutables: Set<string> = new Set<string>(); <ins> let findExecutable = (exeName, path) => { return pfs.fileExists(path).then(exists => { if (!foundExecutables.has(exeName)) { foundExecutables.add(exeName); recommendations.push(...product.exeBasedExtensionTips[exeName]['recommendations']); } }); }; </ins> // Loop through recommended extensions forEach(product.exeBasedExtensionTips, entry => { <del> let executables = entry.value.split(','); // Loop through executables that would result in recommending current extension for (let i = 0; i < executables.length; i++) { if (!foundExecutables.has(executables[i])) { </del> <ins> if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) { return; } </ins> <del> // Loop through paths in PATH to find current executable for (let pathEntry of envpaths) { let fullPath = paths.join(pathEntry, executables[i]); if (process.platform === 'win32') { fullPath += '.exe'; } if (fs.existsSync(fullPath)) { foundExecutables.add(executables[i]); break; } } } if (foundExecutables.has(executables[i])) { this._exeBasedRecommendations.push(entry.key); break; </del> <ins> let exeName = entry.key; if (process.platform === 'win32') { let windowsPath = entry.value['windowsPath']; if (!windowsPath || typeof windowsPath !== 'string') { return; </ins> } <ins> windowsPath = windowsPath.replace('%USERPROFILE%', process.env['USERPROFILE']); findExecutable(exeName, windowsPath); } else { findExecutable(exeName, paths.join('/usr/local/bin', exeName)); findExecutable(exeName, paths.join(homeDir, exeName)); </ins> } }); <del> return this._exeBasedRecommendations; </del> } private setIgnoreRecommendationsConfig(configVal: boolean) {