packager: Module: get rid of callbacks

Summary: By getting rid of callbacks, we get a code that's pretty halved in size, and much easier to read, but we also fix bugs! When some of the code of Module would throw, we wouldn't catch it, meaning that packager would crash entirely. That's the case for when we have a Haste name mistach, for example. This changeste fixes that by instead capturing exceptions through the Promise chain, that bubble up all the way to the `Server` and reasonnably handled. People can then fix the Haste nane mismatch and refresh right away, and it'll work as expected.

Reviewed By: davidaurelio

Differential Revision: D5137408

fbshipit-source-id: b9e938b93e8d23738af49106bbae1fce97d7a5db
This commit is contained in:
Jean Lauliac 2017-05-26 10:11:13 -07:00 committed by Facebook Github Bot
parent 29d2aa65ac
commit 06732d9272
1 changed files with 32 additions and 79 deletions

View File

@ -265,80 +265,44 @@ class Module {
return {...result, id: this._getHasteName(), source}; return {...result, id: this._getHasteName(), source};
} }
_transformCodeForCallback( async _transformCodeFor(
cacheProps: ReadTransformProps, cacheProps: ReadTransformProps,
callback: (error: ?Error, result: ?TransformedCode) => void, ): Promise<TransformedCode> {
) {
const {_transformCode} = this; const {_transformCode} = this;
invariant(_transformCode != null, 'missing code transform funtion'); invariant(_transformCode != null, 'missing code transform funtion');
const {sourceCode, transformOptions} = cacheProps; const {sourceCode, transformOptions} = cacheProps;
return _transformCode(this, sourceCode, transformOptions).then( return await _transformCode(this, sourceCode, transformOptions);
freshResult => process.nextTick(callback, undefined, freshResult),
error => process.nextTick(callback, error),
);
} }
_transformAndStoreCodeGlobally( async _transformAndStoreCodeGlobally(
cacheProps: ReadTransformProps, cacheProps: ReadTransformProps,
globalCache: GlobalTransformCache, globalCache: GlobalTransformCache,
callback: (error: ?Error, result: ?TransformedCode) => void, ): Promise<TransformedCode> {
) { const result = await this._transformCodeFor(cacheProps);
this._transformCodeForCallback( globalCache.store(cacheProps, result);
cacheProps, return result;
(transformError, transformResult) => {
if (transformError != null) {
callback(transformError);
return;
}
invariant(
transformResult != null,
'Inconsistent state: there is no error, but no results either.',
);
globalCache.store(cacheProps, transformResult);
callback(undefined, transformResult);
},
);
} }
_getTransformedCode( async _getTransformedCode(
cacheProps: ReadTransformProps, cacheProps: ReadTransformProps,
callback: (error: ?Error, result: ?TransformedCode) => void, ): Promise<TransformedCode> {
) {
const {_globalCache} = this; const {_globalCache} = this;
if (_globalCache == null || !_globalCache.shouldFetch(cacheProps)) { if (_globalCache == null || !_globalCache.shouldFetch(cacheProps)) {
this._transformCodeForCallback(cacheProps, callback); return await this._transformCodeFor(cacheProps);
return;
} }
_globalCache.fetch(cacheProps).then( const globalCachedResult = await _globalCache.fetch(cacheProps);
globalCachedResult => if (globalCachedResult != null) {
process.nextTick(() => { return globalCachedResult;
if (globalCachedResult == null) { }
this._transformAndStoreCodeGlobally( return await this._transformAndStoreCodeGlobally(cacheProps, _globalCache);
cacheProps,
_globalCache,
callback,
);
return;
}
callback(undefined, globalCachedResult);
}),
globalCacheError => process.nextTick(() => callback(globalCacheError)),
);
} }
_getAndCacheTransformedCode( async _getAndCacheTransformedCode(
cacheProps: ReadTransformProps, cacheProps: ReadTransformProps,
callback: (error: ?Error, result: ?TransformedCode) => void, ): Promise<TransformedCode> {
) { const result = await this._getTransformedCode(cacheProps);
this._getTransformedCode(cacheProps, (error, result) => { this._options.transformCache.writeSync({...cacheProps, result});
if (error) { return result;
callback(error);
return;
}
invariant(result != null, 'missing result');
this._options.transformCache.writeSync({...cacheProps, result});
callback(undefined, result);
});
} }
/** /**
@ -411,30 +375,19 @@ class Module {
if (promise != null) { if (promise != null) {
return promise; return promise;
} }
const freshPromise = Promise.resolve().then(() => { const freshPromise = (async () => {
const cacheProps = this._getCacheProps(transformOptions, key); const cacheProps = this._getCacheProps(transformOptions, key);
return new Promise((resolve, reject) => { const freshResult = await this._getAndCacheTransformedCode(cacheProps);
this._getAndCacheTransformedCode( const finalResult = this._finalizeReadResult(
cacheProps, cacheProps.sourceCode,
(transformError, freshResult) => { freshResult,
if (transformError) { );
reject(transformError); this._readResultsByOptionsKey.set(key, {
return; result: finalResult,
} outdatedDependencies: [],
invariant(freshResult != null, 'inconsistent state');
resolve(
this._finalizeReadResult(cacheProps.sourceCode, freshResult),
);
},
);
}).then(result => {
this._readResultsByOptionsKey.set(key, {
result,
outdatedDependencies: [],
});
return result;
}); });
}); return finalResult;
})();
this._readPromises.set(key, freshPromise); this._readPromises.set(key, freshPromise);
return freshPromise; return freshPromise;
} }