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

View File

@ -27,6 +27,7 @@ import UserProvider from './UserProvider';
import EmojiProvider from './EmojiProvider'; import EmojiProvider from './EmojiProvider';
import NotifProvider from './NotifProvider'; import NotifProvider from './NotifProvider';
import Promise from 'bluebird'; import Promise from 'bluebird';
import {timeout} from "../utils/promise";
export type SelectionRange = { export type SelectionRange = {
beginning: boolean, // whether the selection is in the first block of the editor or not 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 while the user is interacting with the list, which makes it difficult
to predict whether an action will actually do what is intended to predict whether an action will actually do what is intended
*/ */
const completionsList = await Promise.all( const completionsList = await Promise.all(this.providers.map(provider => {
// Array of inspections of promises that might timeout. Instead of allowing a return timeout(provider.getCompletions(query, selection, force), null, PROVIDER_COMPLETION_TIMEOUT);
// 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 => // map then filter to maintain the index for the map-operation, for this.providers to line up
provider return completionsList.map((completions, i) => {
.getCompletions(query, selection, force) if (!completions || !completions.length) return;
.timeout(PROVIDER_COMPLETION_TIMEOUT)
.reflect(),
),
);
return completionsList.filter(
(inspection) => inspection.isFulfilled(),
).map((completionsState, i) => {
return { return {
completions: completionsState.value(), completions,
provider: this.providers[i], provider: this.providers[i],
/* the currently matched "command" the completer tried to complete /* 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), 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 { showGroupAddRoomDialog } from '../../GroupAddressPicker';
import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks"; import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks";
import {Group} from "matrix-js-sdk"; import {Group} from "matrix-js-sdk";
import {sleep} from "../../utils/promise"; import {allSettled, sleep} from "../../utils/promise";
const LONG_DESC_PLACEHOLDER = _td( const LONG_DESC_PLACEHOLDER = _td(
`<h1>HTML for your community's page</h1> `<h1>HTML for your community's page</h1>
@ -99,11 +99,10 @@ const CategoryRoomList = createReactClass({
onFinished: (success, addrs) => { onFinished: (success, addrs) => {
if (!success) return; if (!success) return;
const errorList = []; const errorList = [];
Promise.all(addrs.map((addr) => { allSettled(addrs.map((addr) => {
return GroupStore return GroupStore
.addRoomToGroupSummary(this.props.groupId, addr.address) .addRoomToGroupSummary(this.props.groupId, addr.address)
.catch(() => { errorList.push(addr.address); }) .catch(() => { errorList.push(addr.address); });
.reflect();
})).then(() => { })).then(() => {
if (errorList.length === 0) { if (errorList.length === 0) {
return; return;
@ -276,11 +275,10 @@ const RoleUserList = createReactClass({
onFinished: (success, addrs) => { onFinished: (success, addrs) => {
if (!success) return; if (!success) return;
const errorList = []; const errorList = [];
Promise.all(addrs.map((addr) => { allSettled(addrs.map((addr) => {
return GroupStore return GroupStore
.addUserToGroupSummary(addr.address) .addUserToGroupSummary(addr.address)
.catch(() => { errorList.push(addr.address); }) .catch(() => { errorList.push(addr.address); });
.reflect();
})).then(() => { })).then(() => {
if (errorList.length === 0) { if (errorList.length === 0) {
return; 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 // if we already have the event in question, TimelineWindow.load
// returns a resolved promise. // returns a resolved promise.
// //
@ -1074,9 +1072,13 @@ const TimelinePanel = createReactClass({
// quite slow. So we detect that situation and shortcut straight to // quite slow. So we detect that situation and shortcut straight to
// calling _reloadEvents and updating the state. // 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(); onLoaded();
} else { } else {
const prom = this._timelineWindow.load(eventId, INITIAL_SIZE);
this.setState({ this.setState({
events: [], events: [],
liveEvents: [], liveEvents: [],
@ -1084,11 +1086,8 @@ const TimelinePanel = createReactClass({
canForwardPaginate: false, canForwardPaginate: false,
timelineLoading: true, timelineLoading: true,
}); });
prom.then(onLoaded, onError);
prom = prom.then(onLoaded, onError);
} }
prom.done();
}, },
// handle the completion of a timeline load or localEchoUpdate, by // 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.id = "instance-" + Math.random() + Date.now();
this.index = 0; this.index = 0;
this.db = null; this.db = null;
// these promises are cleared as soon as fulfilled
this.flushPromise = null; this.flushPromise = null;
// set if flush() is called whilst one is ongoing // set if flush() is called whilst one is ongoing
this.flushAgainPromise = null; this.flushAgainPromise = null;
@ -208,15 +210,15 @@ class IndexedDBLogStore {
*/ */
flush() { flush() {
// check if a flush() operation is ongoing // check if a flush() operation is ongoing
if (this.flushPromise && this.flushPromise.isPending()) { if (this.flushPromise) {
if (this.flushAgainPromise && this.flushAgainPromise.isPending()) { if (this.flushAgainPromise) {
// this is the 3rd+ time we've called flush() : return the same // this is the 3rd+ time we've called flush() : return the same promise.
// promise.
return this.flushAgainPromise; return this.flushAgainPromise;
} }
// queue up a flush to occur immediately after the pending one // queue up a flush to occur immediately after the pending one completes.
// completes.
this.flushAgainPromise = this.flushPromise.then(() => { this.flushAgainPromise = this.flushPromise.then(() => {
// clear this.flushAgainPromise
this.flushAgainPromise = null;
return this.flush(); return this.flush();
}); });
return this.flushAgainPromise; return this.flushAgainPromise;
@ -232,12 +234,16 @@ class IndexedDBLogStore {
} }
const lines = this.logger.flush(); const lines = this.logger.flush();
if (lines.length === 0) { if (lines.length === 0) {
// clear this.flushPromise
this.flushPromise = null;
resolve(); resolve();
return; return;
} }
const txn = this.db.transaction(["logs", "logslastmod"], "readwrite"); const txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
const objStore = txn.objectStore("logs"); const objStore = txn.objectStore("logs");
txn.oncomplete = (event) => { txn.oncomplete = (event) => {
// clear this.flushPromise
this.flushPromise = null;
resolve(); resolve();
}; };
txn.onerror = (event) => { txn.onerror = (event) => {

View File

@ -47,3 +47,20 @@ export function defer(): {resolve: () => {}, reject: () => {}, promise: Promise}
return {resolve, reject, 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,
}));
}));
}