Skip to content

Commit

Permalink
Utilize Promise.withResolvers (#56764)
Browse files Browse the repository at this point in the history
This utilizes `Promise.withResolvers` in a few places where it was done the old way. This also rearranges some imports and typings.
  • Loading branch information
wyattjoh committed Oct 12, 2023
1 parent 0b5251c commit 961fd01
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 43 deletions.
6 changes: 5 additions & 1 deletion packages/next/src/lib/polyfill-promise-with-resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ if (
!('withResolvers' in Promise) ||
typeof Promise.withResolvers !== 'function'
) {
Promise.withResolvers = <T>() => {
Promise.withResolvers = <T>(): {
readonly promise: Promise<T>
readonly resolve: (value: T | PromiseLike<T>) => void
readonly reject: (reason: any) => void
} => {
let resolvers: {
resolve: (value: T | PromiseLike<T>) => void
reject: (reason: any) => void
Expand Down
31 changes: 17 additions & 14 deletions packages/next/src/server/dev/next-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ import type {
NextUrlWithParsedQuery,
} from '../request-meta'
import type { DevBundlerService } from '../lib/dev-bundler-service'
import type { IncrementalCache } from '../lib/incremental-cache'
import type { UnwrapPromise } from '../../lib/coalesced-function'
import type { NodeNextResponse, NodeNextRequest } from '../base-http/node'
import type { RouteEnsurer } from '../future/route-matcher-managers/dev-route-matcher-manager'
import type { PagesManifest } from '../../build/webpack/plugins/pages-manifest-plugin'

import fs from 'fs'
import { Worker } from 'next/dist/compiled/jest-worker'
Expand All @@ -39,26 +44,21 @@ import { setGlobal } from '../../trace'
import { findPageFile } from '../lib/find-page-file'
import { getNodeOptionsWithoutInspect } from '../lib/utils'
import { withCoalescedInvoke } from '../../lib/coalesced-function'
import type { UnwrapPromise } from '../../lib/coalesced-function'
import { loadDefaultErrorComponents } from '../load-default-error-components'
import { DecodeError, MiddlewareNotFoundError } from '../../shared/lib/utils'
import * as Log from '../../build/output/log'
import isError, { getProperError } from '../../lib/is-error'
import type { NodeNextResponse, NodeNextRequest } from '../base-http/node'
import { isMiddlewareFile } from '../../build/utils'
import { formatServerError } from '../../lib/format-server-error'
import { DevRouteMatcherManager } from '../future/route-matcher-managers/dev-route-matcher-manager'
import type { RouteEnsurer } from '../future/route-matcher-managers/dev-route-matcher-manager'
import { DevPagesRouteMatcherProvider } from '../future/route-matcher-providers/dev/dev-pages-route-matcher-provider'
import { DevPagesAPIRouteMatcherProvider } from '../future/route-matcher-providers/dev/dev-pages-api-route-matcher-provider'
import { DevAppPageRouteMatcherProvider } from '../future/route-matcher-providers/dev/dev-app-page-route-matcher-provider'
import { DevAppRouteRouteMatcherProvider } from '../future/route-matcher-providers/dev/dev-app-route-route-matcher-provider'
import type { PagesManifest } from '../../build/webpack/plugins/pages-manifest-plugin'
import { NodeManifestLoader } from '../future/route-matcher-providers/helpers/manifest-loaders/node-manifest-loader'
import { BatchedFileReader } from '../future/route-matcher-providers/dev/helpers/file-reader/batched-file-reader'
import { DefaultFileReader } from '../future/route-matcher-providers/dev/helpers/file-reader/default-file-reader'
import { NextBuildContext } from '../../build/build-context'
import type { IncrementalCache } from '../lib/incremental-cache'
import LRUCache from 'next/dist/compiled/lru-cache'
import { getMiddlewareRouteMatcher } from '../../shared/lib/router/utils/middleware-route-matcher'

Expand All @@ -85,8 +85,11 @@ export interface Options extends ServerOptions {
}

export default class DevServer extends Server {
private devReady: Promise<void>
private setDevReady?: Function
/**
* The promise that resolves when the server is ready. When this is unset
* the server is ready.
*/
private ready? = Promise.withResolvers<void>()
protected sortedRoutes?: string[]
private pagesDir?: string
private appDir?: string
Expand Down Expand Up @@ -145,9 +148,6 @@ export default class DevServer extends Server {
this.renderOpts.appDirDevErrorLogger = (err: any) =>
this.logErrorWithOriginalStack(err, 'app-dir')
;(this.renderOpts as any).ErrorDebug = ReactDevOverlay
this.devReady = new Promise((resolve) => {
this.setDevReady = resolve
})
this.staticPathsCache = new LRUCache({
// 5MB
max: 5 * 1024 * 1024,
Expand Down Expand Up @@ -268,7 +268,9 @@ export default class DevServer extends Server {
await super.prepareImpl()
await this.runInstrumentationHookIfAvailable()
await this.matchers.reload()
this.setDevReady!()

this.ready?.resolve()
this.ready = undefined

// This is required by the tracing subsystem.
setGlobal('appDir', this.appDir)
Expand Down Expand Up @@ -428,7 +430,7 @@ export default class DevServer extends Server {
res: BaseNextResponse,
parsedUrl?: NextUrlWithParsedQuery
): Promise<void> {
await this.devReady
await this.ready?.promise
return await super.handleRequest(req, res, parsedUrl)
}

Expand All @@ -437,7 +439,7 @@ export default class DevServer extends Server {
res: NodeNextResponse,
parsedUrl: UrlWithParsedQuery
): Promise<void> {
await this.devReady
await this.ready?.promise

const { basePath } = this.nextConfig
let originalPathname: string | null = null
Expand Down Expand Up @@ -748,7 +750,8 @@ export default class DevServer extends Server {
appPaths?: ReadonlyArray<string> | null
shouldEnsure: boolean
}): Promise<FindComponentsResult | null> {
await this.devReady
await this.ready?.promise

const compilationErr = await this.getCompilationError(page)
if (compilationErr) {
// Wrap build errors so that they don't get logged again
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// This takes advantage of `Promise.withResolvers` which is polyfilled in
// this imported module.
import '../../../lib/polyfill-promise-with-resolvers'

import { isDynamicRoute } from '../../../shared/lib/router/utils'
import type { RouteKind } from '../route-kind'
Expand Down Expand Up @@ -44,10 +46,8 @@ export class DefaultRouteMatcherManager implements RouteMatcherManager {

private previousMatchers: ReadonlyArray<RouteMatcher> = []
public async reload() {
let callbacks: { resolve: Function; reject: Function }
this.waitTillReadyPromise = new Promise((resolve, reject) => {
callbacks = { resolve, reject }
})
const { promise, resolve, reject } = Promise.withResolvers<void>()
this.waitTillReadyPromise = promise

// Grab the compilation ID for this run, we'll verify it at the end to
// ensure that if any routes were added before reloading is finished that
Expand Down Expand Up @@ -182,11 +182,11 @@ export class DefaultRouteMatcherManager implements RouteMatcherManager {
)
}
} catch (err) {
callbacks!.reject(err)
reject(err)
} finally {
// The compilation ID matched, so mark the complication as finished.
this.lastCompilationID = compilationID
callbacks!.resolve()
resolve()
}
}

Expand Down
13 changes: 0 additions & 13 deletions packages/next/src/server/image-optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,16 +794,3 @@ export async function getImageSize(
const { width, height } = imageSizeOf(buffer)
return { width, height }
}

export class Deferred<T> {
promise: Promise<T>
resolve!: (value: T) => void
reject!: (error?: Error) => void

constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
})
}
}
13 changes: 5 additions & 8 deletions packages/next/src/server/response-cache/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,11 @@ export default class WebResponseCache {
return pendingResponse
}

let resolver: (cacheEntry: ResponseCacheEntry | null) => void = () => {}
let rejecter: (error: Error) => void = () => {}
const promise: Promise<ResponseCacheEntry | null> = new Promise(
(resolve, reject) => {
resolver = resolve
rejecter = reject
}
)
const {
promise,
resolve: resolver,
reject: rejecter,
} = Promise.withResolvers<ResponseCacheEntry | null>()
if (pendingResponseKey) {
this.pendingResponses.set(pendingResponseKey, promise)
}
Expand Down

0 comments on commit 961fd01

Please sign in to comment.