Radosław Miernik
Open source? Embrace, understand, develop.
(Okay, let’s make it a few steps instead.)
THERE IS NO TIME! WE HAVE TO GET RID OF FIBERS!
Everything is at radekmie.dev.
// Create the collection.
import { Mongo } from 'meteor/mongo';
const Posts = new Mongo.Collection('posts');
Collection#insert returns the inserted ID immediately both on the client and the server.
// Create a new post.
const result = Posts.insert({
title: 'Clickbait here!',
text: 'Have you ever...',
});
// What is in the `result`?
console.log(result);
// Create the collection.
import { MongoClient } from 'mongodb';
const client = new MongoClient('mongodb://...');
const Posts = client.db().collection('posts');
Collection#insert returns a promise of the response (it includes the inserted ID).
// Create a new post.
const result = await Posts.insertOne({
title: 'Clickbait here!',
text: 'Have you ever...',
});
// What is in the `result`?
console.log(result);
await
?// EXTREMELY simplified version.
MongoConnection.prototype._insert =
function (collection_name, document, callback) {
this.rawCollection(collection_name)
.insertOne(document)
.then(({ insertedId }) => { callback(null, insertedId); })
.catch(error => { callback(error, null); });
};
Meteor#wrapAsync magically got rid of the promise...? Let's look into it!
// Exact implementation.
_.each(["insert", "update", "remove", "dropCollection", "dropDatabase"], function (method) {
MongoConnection.prototype[method] = function (/* arguments */) {
var self = this;
return Meteor.wrapAsync(self["_" + method]).apply(self, arguments);
};
});
// EXTREMELY simplified version.
if (Meteor.isServer)
var Future = Npm.require('fibers/future');
Meteor.wrapAsync = function (fn, context) {
return function (/* ...args, callback */) {
if (!callback) {
if (Meteor.isClient) {
callback = logErr; // Logs the error (if any).
} else {
var future = new Future();
callback = future.resolver();
}
}
callback = Meteor.bindEnvironment(callback);
var result = fn.apply(context || this, [...args, callback]);
return future ? future.wait() : result;
};
};
FIBERS!
*snip*
*Async
MongoDB methods (#12028).
await
to all database operations (i.e., make the surrounding functions async
).Fiber
and Future
occurrences from your code. In most cases, it'll be as easy as one await
.
Promise.await
, Promise#await
, and other Meteor-specific functions, as they rely on Fibers.
?
await
without async
declare module 'meteor/promise' {
export class Promise extends globalThis.Promise {
static async any, This, Args extends any[]>(
fn: Fn,
allowReuseOfCurrentFiber?: boolean,
): (this: This, ...args: Args) => Promise>;
static asyncApply any, This, Args extends any[]>(
fn: Fn,
context: This,
args: Args,
allowReuseOfCurrentFiber?: boolean,
): Promise>;
static await(value: PromiseLike): T;
static awaitAll(values: Iterable>): T[];
await(): T;
}
}
All of these are Meteor-specific. The less you use them, the easier it will be to migrate off the Fibers.
By Radosław Miernik
...with this one weird trick! (Meteor NYC, August 16, 2022.)