Replace bluebird specific promise things. Fix uses of sync promise code.

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2019-11-14 13:52:17 +00:00
parent 5c24547ef5
commit 54dcaf1302
6 changed files with 53 additions and 38 deletions

View file

@ -21,6 +21,7 @@ import MultiInviter from './utils/MultiInviter';
import { _t } from './languageHandler';
import MatrixClientPeg from './MatrixClientPeg';
import GroupStore from './stores/GroupStore';
import {allSettled} from "./utils/promise";
export function showGroupInviteDialog(groupId) {
return new Promise((resolve, reject) => {
@ -118,7 +119,7 @@ function _onGroupInviteFinished(groupId, addrs) {
function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
const matrixClient = MatrixClientPeg.get();
const errorList = [];
return Promise.all(addrs.map((addr) => {
return allSettled(addrs.map((addr) => {
return GroupStore
.addRoomToGroup(groupId, addr.address, addRoomsPublicly)
.catch(() => { errorList.push(addr.address); })
@ -138,7 +139,7 @@ function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) {
groups.push(groupId);
return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.related_groups', {groups}, '');
}
}).reflect();
});
})).then(() => {
if (errorList.length === 0) {
return;

View file

@ -27,6 +27,7 @@ import UserProvider from './UserProvider';
import EmojiProvider from './EmojiProvider';
import NotifProvider from './NotifProvider';
import Promise from 'bluebird';
import {timeout} from "../utils/promise";
export type SelectionRange = {
beginning: boolean, // whether the selection is in the first block of the editor or not
@ -77,23 +78,16 @@ export default class Autocompleter {
while the user is interacting with the list, which makes it difficult
to predict whether an action will actually do what is intended
*/
const completionsList = await Promise.all(
// Array of inspections of promises that might timeout. Instead of allowing a
// single timeout to reject the Promise.all, reflect each one and once they've all
// settled, filter for the fulfilled ones
this.providers.map(provider =>
provider
.getCompletions(query, selection, force)
.timeout(PROVIDER_COMPLETION_TIMEOUT)
.reflect(),
),
);
const completionsList = await Promise.all(this.providers.map(provider => {
return timeout(provider.getCompletions(query, selection, force), null, PROVIDER_COMPLETION_TIMEOUT);
}));
// map then filter to maintain the index for the map-operation, for this.providers to line up
return completionsList.map((completions, i) => {
if (!completions || !completions.length) return;
return completionsList.filter(
(inspection) => inspection.isFulfilled(),
).map((completionsState, i) => {
return {
completions: completionsState.value(),
completions,
provider: this.providers[i],
/* the currently matched "command" the completer tried to complete
@ -102,6 +96,6 @@ export default class Autocompleter {
*/
command: this.providers[i].getCurrentCommand(query, selection, force),
};
});
}).filter(Boolean);
}
}

View file

@ -38,7 +38,7 @@ import FlairStore from '../../stores/FlairStore';
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks";
import {Group} from "matrix-js-sdk";
import {sleep} from "../../utils/promise";
import {allSettled, sleep} from "../../utils/promise";
const LONG_DESC_PLACEHOLDER = _td(
`<h1>HTML for your community's page</h1>
@ -99,11 +99,10 @@ const CategoryRoomList = createReactClass({
onFinished: (success, addrs) => {
if (!success) return;
const errorList = [];
Promise.all(addrs.map((addr) => {
allSettled(addrs.map((addr) => {
return GroupStore
.addRoomToGroupSummary(this.props.groupId, addr.address)
.catch(() => { errorList.push(addr.address); })
.reflect();
.catch(() => { errorList.push(addr.address); });
})).then(() => {
if (errorList.length === 0) {
return;
@ -276,11 +275,10 @@ const RoleUserList = createReactClass({
onFinished: (success, addrs) => {
if (!success) return;
const errorList = [];
Promise.all(addrs.map((addr) => {
allSettled(addrs.map((addr) => {
return GroupStore
.addUserToGroupSummary(addr.address)
.catch(() => { errorList.push(addr.address); })
.reflect();
.catch(() => { errorList.push(addr.address); });
})).then(() => {
if (errorList.length === 0) {
return;

View file

@ -1064,8 +1064,6 @@ const TimelinePanel = createReactClass({
});
};
let prom = this._timelineWindow.load(eventId, INITIAL_SIZE);
// if we already have the event in question, TimelineWindow.load
// returns a resolved promise.
//
@ -1074,9 +1072,13 @@ const TimelinePanel = createReactClass({
// quite slow. So we detect that situation and shortcut straight to
// calling _reloadEvents and updating the state.
if (prom.isFulfilled()) {
const timeline = this.props.timelineSet.getTimelineForEvent(eventId);
if (timeline) {
// This is a hot-path optimization by skipping a promise tick
// by repeating a no-op sync branch in TimelineSet.getTimelineForEvent & MatrixClient.getEventTimeline
onLoaded();
} else {
const prom = this._timelineWindow.load(eventId, INITIAL_SIZE);
this.setState({
events: [],
liveEvents: [],
@ -1084,11 +1086,8 @@ const TimelinePanel = createReactClass({
canForwardPaginate: false,
timelineLoading: true,
});
prom = prom.then(onLoaded, onError);
prom.then(onLoaded, onError);
}
prom.done();
},
// handle the completion of a timeline load or localEchoUpdate, by

View file

@ -136,6 +136,8 @@ class IndexedDBLogStore {
this.id = "instance-" + Math.random() + Date.now();
this.index = 0;
this.db = null;
// these promises are cleared as soon as fulfilled
this.flushPromise = null;
// set if flush() is called whilst one is ongoing
this.flushAgainPromise = null;
@ -208,15 +210,15 @@ class IndexedDBLogStore {
*/
flush() {
// check if a flush() operation is ongoing
if (this.flushPromise && this.flushPromise.isPending()) {
if (this.flushAgainPromise && this.flushAgainPromise.isPending()) {
// this is the 3rd+ time we've called flush() : return the same
// promise.
if (this.flushPromise) {
if (this.flushAgainPromise) {
// this is the 3rd+ time we've called flush() : return the same promise.
return this.flushAgainPromise;
}
// queue up a flush to occur immediately after the pending one
// completes.
// queue up a flush to occur immediately after the pending one completes.
this.flushAgainPromise = this.flushPromise.then(() => {
// clear this.flushAgainPromise
this.flushAgainPromise = null;
return this.flush();
});
return this.flushAgainPromise;
@ -232,12 +234,16 @@ class IndexedDBLogStore {
}
const lines = this.logger.flush();
if (lines.length === 0) {
// clear this.flushPromise
this.flushPromise = null;
resolve();
return;
}
const txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
const objStore = txn.objectStore("logs");
txn.oncomplete = (event) => {
// clear this.flushPromise
this.flushPromise = null;
resolve();
};
txn.onerror = (event) => {

View file

@ -47,3 +47,20 @@ export function defer(): {resolve: () => {}, reject: () => {}, promise: Promise}
return {resolve, reject, promise};
}
// Promise.allSettled polyfill until browser support is stable in Firefox
export function allSettled(promises: Promise[]): {status: string, value?: any, reason?: any}[] {
if (Promise.allSettled) {
return Promise.allSettled(promises);
}
return Promise.all(promises.map((promise) => {
return promise.then(value => ({
status: "fulfilled",
value,
})).catch(reason => ({
status: "rejected",
reason,
}));
}));
}