forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prebid core & currency module: fix race condition on slow fetch of cu…
…rrency conversion file The currency module hooks into the auction's `addBidResponse` flow to modify bid responses with currency info. To do this it needs to fetch conversion rates from the network, but the auction expects `addBidResponse` to complete synchronously, and things break down if all bidder network calls complete before the currency file fetch. This fix allows the `addBidResponse` hook to return a promise. If it does, the auction will wait for it before ending. Addresses prebid#7765
- Loading branch information
Showing
6 changed files
with
315 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const orig = {}; | ||
['resolve', 'reject', 'all', 'race', 'allSettled'].forEach((k) => orig[k] = Promise[k].bind(Promise)) | ||
|
||
// Callbacks attached through Promise.resolve(value).then(...) will usually | ||
// not execute immediately even if `value` is immediately available. This | ||
// breaks tests that were written before promises even though they are semantically still valid. | ||
// They can be made to work by making promises quasi-synchronous. | ||
|
||
export function SyncPromise(value, fail = false) { | ||
if (value instanceof SyncPromise) { | ||
return value; | ||
} else if (typeof value === 'object' && typeof value.then === 'function') { | ||
return resolve(value); | ||
} else { | ||
Object.assign(this, { | ||
then: function (cb, err) { | ||
const handler = fail ? err : cb; | ||
if (handler != null) { | ||
return new SyncPromise(handler(value)); | ||
} else { | ||
return this; | ||
} | ||
}, | ||
catch: function (cb) { | ||
if (fail) { | ||
return new SyncPromise(cb(value)) | ||
} else { | ||
return this; | ||
} | ||
}, | ||
finally: function (cb) { | ||
cb(); | ||
return this; | ||
}, | ||
__value: fail ? {status: 'rejected', reason: value} : {status: 'fulfilled', value} | ||
}) | ||
} | ||
} | ||
|
||
Object.assign(SyncPromise, { | ||
resolve: (val) => new SyncPromise(val), | ||
reject: (val) => new SyncPromise(val, true), | ||
race: (promises) => promises.find((p) => p instanceof SyncPromise) || orig.race(promises), | ||
allSettled: (promises) => { | ||
if (promises.every((p) => p instanceof SyncPromise)) { | ||
return new SyncPromise(promises.map((p) => p.__value)) | ||
} else { | ||
return orig.allSettled(promises); | ||
} | ||
}, | ||
all: (promises) => { | ||
if (promises.every((p) => p instanceof SyncPromise)) { | ||
return SyncPromise.allSettled(promises).then((result) => { | ||
const err = result.find((r) => r.status === 'fulfilled'); | ||
if (err != null) { | ||
return new SyncPromise(err.reason, true); | ||
} else { | ||
return new SyncPromise(result.map((r) => r.value)) | ||
} | ||
}) | ||
} else { | ||
return orig.all(promises); | ||
} | ||
} | ||
}) | ||
|
||
export function synchronizePromise(sandbox) { | ||
Object.keys(orig).forEach((k) => { | ||
sandbox.stub(window.Promise, k).callsFake(SyncPromise[k]); | ||
}) | ||
} |
Oops, something went wrong.