- Notifications
You must be signed in to change notification settings - Fork13k
Description
This may sound like a silly report -- please bear with me (:
I'm the author ofsynchronous-promise, an A+ Promise-like implementation which doesn't defer (and allows pausing and resuming), so makes testing certain scenarios clearer / easier. Mostly, it's worked well with TypeScript because of how awesome TypeScript's async/await logic is.
The problem isvery specific is this: ifSynchronousPromise
is installed globally (overridingPromise
-- and we could do this so that client code returning aPromise
actually returns aSynchronousPromise
, during test-time),and aSynchronousPromise
resolution happens in asetTimeout
, the TS generator function also makes use ofSynchronousPromise
and doesn't complete awaiting the following:
import{SynchronousPromise}from"./index";import{expect}from'chai';// install SynchronousPromise globallyglobal.Promise=SynchronousPromise;describe("typescript async/await",()=>{it("should not hang",asyncfunction(){// Arrange// ActawaitnewSynchronousPromise(function(resolve,reject){setTimeout(()=>{resolve("done!");},0);});})});
The problem seems to track down to the generatedgenerator
code which expects aP
(short-handed globalPromise
) to defer. If I comment out the line:
// global.Promise = SynchronousPromise;
then the test completes, as expected.
Now, I realise that there is a valid argument thatSynchronousPromise
, beingnot async in nature, violates the A+ specification and that this whole issue shouldn't be the problem of TypeScript at all. This is a fair argument, which has a counter-argument: that all TypeScript is a super-set of Javascript. The following Javascript works fine:
"use strict";varexpect=require("chai").expect,sut=require("./index"),SynchronousPromise=sut.SynchronousPromise,describe("with timeout in ctor",()=>{it("should complete when the timeout does",(done)=>{// Arrangevarcaptured,sut=newSynchronousPromise(function(resolve,reject){setTimeout(function(){resolve("moo");},0);}).then(function(result){captured=result;});// Act// AssertsetTimeout(function(){expect(captured).to.equal("moo");done();},500);});});
And debugging the prior snippet has shown that all promises (even the TS-generated / wrapper ones created for async/await) are resolved. Execution is simply not continued by the generator.
Expected behavior:
The first snippet (TypeScript) should complete like the second snippet (Javascript)
Actual behavior:
The Javascript completes where the TypeScript does not
Proposed solutions.
- Since the generator function requires deferral, perhaps use
setTimeout
-- however, this is subject to the same problems as testing frameworks likejasmine
can install a testing clock which has to be manually advanced by the test code. - "var off" the global Promise implementation before allowing client code to run and use that version inside the generator code. This seems to be the lowest-hanging fruit for solving this problem, from my point of view.
Of course, the response could also be that this is just an issue withsynchronous-promise
, but it also highlights that TS compiled execution can be interfered with by client code -- which may not be optimal.