Example #1
0
 it('causes a queue to be created the first time it\'s used', () => {
   expect(RelayTaskQueue.mock.instances.length).toBe(0);
   RelayTaskScheduler.enqueue(() => {});
   expect(RelayTaskQueue.mock.instances.length).toBe(1);
   expect(RelayTaskQueue.prototype.constructor).toBeCalledWith(undefined);
   RelayTaskScheduler.enqueue(() => {});
   expect(RelayTaskQueue.mock.instances.length).toBe(1);
 });
 const runIteration = () => {
   // TODO: #9366746: integrate RelayRenderer/Container with GC hold
   warning(
     !pendingQueryTracker.hasPendingQueries(),
     'RelayGarbageCollection: GC is executing during a fetch, but the ' +
     'pending query may rely on data that is collected.'
   );
   let iterations = 0;
   let hasNext = true;
   while (hasNext && (_stepLength < 0 || iterations < _stepLength)) {
     hasNext = run();
     iterations++;
   }
   // This is effectively a (possibly async) `while` loop
   if (hasNext) {
     RelayTaskScheduler.enqueue(runIteration);
   }
 };
  _handleSubtractedQuerySuccess(
    subtractedQuery: RelayQuery.Root,
    result: QueryResult
  ): void {
    this._fetchedSubtractedQuery = true;

    RelayTaskScheduler.enqueue(() => {
      var response = result.response;
      invariant(
        response && typeof response === 'object',
        'RelayPendingQueryTracker: Expected response to be an object, got ' +
        '`%s`.',
        response ? typeof response : response
      );
      this._storeData.handleQueryPayload(
        subtractedQuery,
        response,
        this._forceIndex
      );
    }).done(
      this._markSubtractedQueryAsResolved.bind(this),
      this._markAsRejected.bind(this)
    );
  }
Example #4
0
function runQueries(
  storeData: RelayStoreData,
  queries: Array<RelayQuery.Root>,
  callback: ReadyStateChangeCallback,
  fetchMode: FetchMode,
  profiler: RelayProfileHandler
): Abortable {
  const readyState = new RelayReadyState(callback);

  var remainingFetchMap: {[queryID: string]: PendingFetch} = {};
  var remainingRequiredFetchMap: {[queryID: string]: PendingFetch} = {};

  function onResolved(pendingFetch: PendingFetch) {
    var pendingQuery = pendingFetch.getQuery();
    var pendingQueryID = pendingQuery.getID();
    delete remainingFetchMap[pendingQueryID];
    if (!pendingQuery.isDeferred()) {
      delete remainingRequiredFetchMap[pendingQueryID];
    }

    if (hasItems(remainingRequiredFetchMap)) {
      return;
    }

    if (someObject(remainingFetchMap, query => query.isResolvable())) {
      // The other resolvable query will resolve imminently and call
      // `readyState.update` instead.
      return;
    }

    if (hasItems(remainingFetchMap)) {
      readyState.update({done: false, ready: true, stale: false});
    } else {
      readyState.update({done: true, ready: true, stale: false});
    }
  }

  function onRejected(pendingFetch: PendingFetch, error: Error) {
    readyState.update({error});

    var pendingQuery = pendingFetch.getQuery();
    var pendingQueryID = pendingQuery.getID();
    delete remainingFetchMap[pendingQueryID];
    if (!pendingQuery.isDeferred()) {
      delete remainingRequiredFetchMap[pendingQueryID];
    }
  }

  function canResolve(fetch: PendingFetch): boolean {
    return checkRelayQueryData(
      storeData.getQueuedStore(),
      fetch.getQuery()
    );
  }

  RelayTaskScheduler.enqueue(() => {
    var forceIndex = fetchMode === RelayFetchMode.REFETCH ?
      generateForceIndex() : null;

    splitAndFlattenQueries(queries).forEach(query => {
      var pendingFetch = storeData.getPendingQueryTracker().add(
        {query, fetchMode, forceIndex, storeData}
      );
      var queryID = query.getID();
      remainingFetchMap[queryID] = pendingFetch;
      if (!query.isDeferred()) {
        remainingRequiredFetchMap[queryID] = pendingFetch;
      }
      pendingFetch.getResolvedPromise().then(
        onResolved.bind(null, pendingFetch),
        onRejected.bind(null, pendingFetch)
      );
    });

    if (!hasItems(remainingFetchMap)) {
      readyState.update({done: true, ready: true});
    } else {
      if (!hasItems(remainingRequiredFetchMap)) {
        readyState.update({ready: true});
      } else {
        readyState.update({ready: false});
        resolveImmediate(() => {
          if (storeData.hasCacheManager()) {
            var requiredQueryMap = mapObject(
              remainingRequiredFetchMap,
              value => value.getQuery()
            );
            storeData.readFromDiskCache(requiredQueryMap, {
              onSuccess: () => {
                if (hasItems(remainingRequiredFetchMap)) {
                  readyState.update({ready: true, stale: true});
                }
              },
            });
          } else {
            if (everyObject(remainingRequiredFetchMap, canResolve)) {
              if (hasItems(remainingRequiredFetchMap)) {
                readyState.update({ready: true, stale: true});
              }
            }
          }
        });
      }
    }
    // Stop profiling when queries have been sent to the network layer.
    profiler.stop();
  }).done();

  return {
    abort(): void {
      readyState.update({aborted: true});
    },
  };
}
Example #5
0
 it('uses the injected scheduler to schedule tasks', () => {
   jest.dontMock('RelayTaskQueue');
   const mockTask = () => {};
   RelayTaskScheduler.enqueue(mockTask);
   expect(mockScheduler).toBeCalled();
 });