mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
- fix livedata stub - methods
- revert callAsync code
This commit is contained in:
@@ -237,8 +237,8 @@ export class Connection {
|
||||
|
||||
// Block auto-reload while we're waiting for method responses.
|
||||
if (Meteor.isClient &&
|
||||
Package.reload &&
|
||||
! options.reloadWithOutstanding) {
|
||||
Package.reload &&
|
||||
! options.reloadWithOutstanding) {
|
||||
Package.reload.Reload._onMigrate(retry => {
|
||||
if (! self._readyToMigrate()) {
|
||||
self._retryMigrate = retry;
|
||||
@@ -523,6 +523,13 @@ export class Connection {
|
||||
});
|
||||
}
|
||||
|
||||
_getIsSimulation({isFromCallAsync, alreadyInSimulation}) {
|
||||
if (!isFromCallAsync) {
|
||||
return alreadyInSimulation;
|
||||
}
|
||||
return alreadyInSimulation && DDP._CurrentMethodInvocation._isCallAsyncMethodRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberOf Meteor
|
||||
* @importFromPackage meteor
|
||||
@@ -560,9 +567,44 @@ export class Connection {
|
||||
"Meteor.callAsync() does not accept a callback. You should 'await' the result, or use .then()."
|
||||
);
|
||||
}
|
||||
|
||||
return this.applyAsync(name, args, {
|
||||
isFromCallAsync: true
|
||||
/*
|
||||
* This is necessary because when you call a Promise.then, you're actually calling a bound function by Meteor.
|
||||
*
|
||||
* This is done by this code https://github.com/meteor/meteor/blob/17673c66878d3f7b1d564a4215eb0633fa679017/npm-packages/meteor-promise/promise_client.js#L1-L16. (All the logic below can be removed in the future, when we stop overwriting the
|
||||
* Promise.)
|
||||
*
|
||||
* When you call a ".then()", like "Meteor.callAsync().then()", the global context (inside currentValues)
|
||||
* will be from the call of Meteor.callAsync(), and not the context after the promise is done.
|
||||
*
|
||||
* This means that without this code if you call a stub inside the ".then()", this stub will act as a simulation
|
||||
* and won't reach the server.
|
||||
*
|
||||
* Inside the function _getIsSimulation(), if isFromCallAsync is false, we continue to consider just the
|
||||
* alreadyInSimulation, otherwise, isFromCallAsync is true, we also check the value of callAsyncMethodRunning (by
|
||||
* calling DDP._CurrentMethodInvocation._isCallAsyncMethodRunning()).
|
||||
*
|
||||
* With this, if a stub is running inside a ".then()", it'll know it's not a simulation, because callAsyncMethodRunning
|
||||
* will be false.
|
||||
*
|
||||
* DDP._CurrentMethodInvocation._set() is important because without it, if you have a code like:
|
||||
*
|
||||
* Meteor.callAsync("m1").then(() => {
|
||||
* Meteor.callAsync("m2")
|
||||
* })
|
||||
*
|
||||
* The call the method m2 will act as a simulation and won't reach the server. That's why we reset the context here
|
||||
* before calling everything else.
|
||||
*
|
||||
* */
|
||||
DDP._CurrentMethodInvocation._set();
|
||||
DDP._CurrentMethodInvocation._setCallAsyncMethodRunning(true);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.applyAsync(name, args, { isFromCallAsync: true })
|
||||
.then(result => {
|
||||
DDP._CurrentMethodInvocation._setCallAsyncMethodRunning(false);
|
||||
resolve(result);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -586,7 +628,12 @@ export class Connection {
|
||||
const { stubInvocation, invocation, ...stubOptions } = this._stubCall(name, EJSON.clone(args));
|
||||
|
||||
if (stubOptions.hasStub) {
|
||||
if (!stubOptions.alreadyInSimulation) {
|
||||
if (
|
||||
!this._getIsSimulation({
|
||||
alreadyInSimulation: stubOptions.alreadyInSimulation,
|
||||
isFromCallAsync: stubOptions.isFromCallAsync,
|
||||
})
|
||||
) {
|
||||
this._saveOriginals();
|
||||
}
|
||||
try {
|
||||
@@ -617,7 +664,12 @@ export class Connection {
|
||||
async applyAsync(name, args, options, callback = null) {
|
||||
const { stubInvocation, invocation, ...stubOptions } = this._stubCall(name, EJSON.clone(args), options);
|
||||
if (stubOptions.hasStub) {
|
||||
if (!stubOptions.alreadyInSimulation) {
|
||||
if (
|
||||
!this._getIsSimulation({
|
||||
alreadyInSimulation: stubOptions.alreadyInSimulation,
|
||||
isFromCallAsync: stubOptions.isFromCallAsync,
|
||||
})
|
||||
) {
|
||||
this._saveOriginals();
|
||||
}
|
||||
try {
|
||||
@@ -680,7 +732,12 @@ export class Connection {
|
||||
// If we're in a simulation, stop and return the result we have,
|
||||
// rather than going on to do an RPC. If there was no stub,
|
||||
// we'll end up returning undefined.
|
||||
if (stubCallValue.isFromCallAsync) {
|
||||
if (
|
||||
this._getIsSimulation({
|
||||
alreadyInSimulation,
|
||||
isFromCallAsync: stubCallValue.isFromCallAsync,
|
||||
})
|
||||
) {
|
||||
if (callback) {
|
||||
callback(exception, stubReturnValue);
|
||||
return undefined;
|
||||
|
||||
@@ -315,13 +315,13 @@ Tinytest.addAsync(
|
||||
);
|
||||
|
||||
Meteor.methods({
|
||||
testResolvedPromise(arg) {
|
||||
const invocation1 = DDP._CurrentMethodInvocation.get();
|
||||
async testResolvedPromise(arg) {
|
||||
const invocationRunningFromCallAsync1 = DDP._CurrentMethodInvocation._isCallAsyncMethodRunning();
|
||||
return Promise.resolve(arg).then(result => {
|
||||
const invocation2 = DDP._CurrentMethodInvocation.get();
|
||||
// This equality holds because Promise callbacks are bound to the
|
||||
// dynamic environment where .then was called.
|
||||
if (invocation1 !== invocation2) {
|
||||
const invocationRunningFromCallAsync2 = DDP._CurrentMethodInvocation._isCallAsyncMethodRunning();
|
||||
// What matters here is that both invocations are coming from the same call,
|
||||
// so both of them can be considered a simulation.
|
||||
if (invocationRunningFromCallAsync1 !== invocationRunningFromCallAsync2) {
|
||||
throw new Meteor.Error("invocation mismatch");
|
||||
}
|
||||
return result + " after waiting";
|
||||
|
||||
@@ -20,7 +20,9 @@ export default class LocalCollection {
|
||||
// _id -> document (also containing id)
|
||||
this._docs = new LocalCollection._IdMap;
|
||||
|
||||
this._observeQueue = new Meteor._AsynchronousQueue();
|
||||
this._observeQueue = Meteor.isClient
|
||||
? new Meteor._SynchronousQueue()
|
||||
: new Meteor._AsynchronousQueue();
|
||||
|
||||
this.next_qid = 1; // live query id generator
|
||||
|
||||
|
||||
Reference in New Issue
Block a user