Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions packages/runtime/src/Deferred.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,33 @@ export class Deferred<T = any> implements IStoreValue {
return deferred
}

public id: number
public ctx: Context
public value: IDeferrdValue<T>
public id!: number
public ctx!: Context
public value!: IDeferrdValue<T>

public constructor (ctx: Context, value: IDeferrdValue<T>) {
this.id = 0
this.ctx = ctx
this.value = value
// Plain assignment would invoke inherited setters before these fields
// become own properties.
Object.defineProperties(this, {
id: {
configurable: true,
enumerable: true,
value: 0,
writable: true
},
ctx: {
configurable: true,
enumerable: true,
value: ctx,
writable: true
},
value: {
configurable: true,
enumerable: true,
value,
writable: true
}
})
}

public resolve (value: T): void {
Expand Down
51 changes: 50 additions & 1 deletion packages/test/promise/promise.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,61 @@
/* eslint-disable symbol-description */
/* eslint-disable camelcase */
/* eslint-disable no-extend-native, accessor-pairs */
'use strict'
const assert = require('assert')
const common = require('../common')
const { load } = require('../util')

module.exports = load('promise').then(async test_promise => {
// A resolution
// Deferred state must define its storage as own properties before constructor
// or disposal writes can reach inherited setters.
{
const keys = ['id', 'ctx', 'value']
const originalDescriptors = new Map(
keys.map(key => [key, Object.getOwnPropertyDescriptor(Object.prototype, key)])
)
Object.defineProperties(
Object.prototype,
Object.fromEntries(
keys.map(key => [
key,
{
configurable: true,
set () {
throw new Error(`inherited ${key} setter invoked`)
}
}
])
)
)

try {
const resolvedPromise = test_promise.createPromise()
test_promise.concludeCurrentPromise(42, true)
assert.strictEqual(await resolvedPromise, 42)

const rejectedPromise = test_promise.createPromise()
test_promise.concludeCurrentPromise('rejected', false)
let rejection
try {
await rejectedPromise
} catch (err) {
rejection = err
}
assert.strictEqual(rejection, 'rejected')
} finally {
for (const key of keys) {
const descriptor = originalDescriptors.get(key)
if (descriptor) {
Object.defineProperty(Object.prototype, key, descriptor)
} else {
delete Object.prototype[key]
}
}
}
}

// A resolution
{
const expected_result = 42
const promise = test_promise.createPromise()
Expand Down