Last active
August 29, 2015 14:22
-
-
Save marcoscaceres/29275058c3684b354e3c to your computer and use it in GitHub Desktop.
async.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This Source Code Form is subject to the terms of the Mozilla Public | |
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | |
* You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
/* | |
* This is an approximate implementation of ES7's async-await pattern. | |
* see: https://github.com/tc39/ecmascript-asyncawait | |
* | |
* It allows for simple creation of async function and "tasks". | |
* | |
* For example: | |
* | |
* var myThinger = { | |
* doAsynThing: async(function*(url){ | |
* var result = yield fetch(url); | |
* return process(result); | |
* }); | |
* } | |
* | |
* And Task-like things can be created as follows: | |
* | |
* var myTask = async(function*{ | |
* var result = yield fetch(url); | |
* return result; | |
* }); | |
* //returns a promise | |
* | |
* myTask().then(doSomethingElse); | |
* | |
*/ | |
(function(exports) { | |
"use strict"; | |
function async(func, self) { | |
return function asyncFunction() { | |
const functionArgs = Array.from(arguments); | |
return new Promise(function(resolve, reject) { | |
var gen; | |
if (typeof func !== "function") { | |
reject(new TypeError("Expected a Function.")); | |
} | |
//not a generator, wrap it. | |
if (func.constructor.name !== "GeneratorFunction") { | |
gen = (function*() { | |
return func.apply(self, functionArgs); | |
}()); | |
} else { | |
gen = func.apply(self, functionArgs); | |
} | |
try { | |
step(gen.next(undefined)); | |
} catch (err) { | |
reject(err); | |
} | |
function step({value, done}) { | |
if (done) { | |
return resolve(value); | |
} | |
if (value instanceof Promise) { | |
return value.then( | |
result => step(gen.next(result)), | |
error => { | |
try { | |
step(gen.throw(error)); | |
} catch (err) { | |
throw err; | |
} | |
} | |
).catch(err => reject(err)); | |
} | |
step(gen.next(value)); | |
} | |
}); | |
}; | |
} | |
exports.async = async; | |
}(this || self)); | |
// Tests | |
let expected = function(result) { | |
console.assert(result instanceof Error, 'Expected exception.'); | |
}; | |
[undefined, null, 1, [], {}, 'string'] | |
.forEach(invalidType => { | |
async(invalidType)().then( | |
(s) => expected, (err) => expected | |
); | |
}); | |
let expectedPass = function(result) { | |
let msg = `Expect pass. Got ${result}`; | |
console.assert(result === 'pass', msg); | |
}; | |
async(function* () { | |
let x = yield Promise.resolve('testing'); | |
console.assert(x === 'testing', 'Expected testing'); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
let x = yield Promise.resolve('testing'); | |
let y = yield Promise.resolve(x + '123'); | |
let z = yield y + '456'; | |
console.assert(z === 'testing123456', `Expected testing123456. Got: ${z}`); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
let x = yield Promise.resolve('testing'); | |
let y = yield Promise.resolve(x + '123'); | |
let z = yield Promise.resolve(y + '456'); | |
console.assert(z === 'testing123456', `Expected testing123456. Got: ${z}`); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
//Testing try/catch | |
async(function* () { | |
let err; | |
try { | |
let x = yield Promise.reject(new Error('testing111')); | |
} catch (err) { | |
console.assert(err.message === 'testing111', 'Expected testing111'); | |
} | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
let err; | |
try { | |
let x = yield Promise.reject(new Error('testing111')); | |
} catch (err) { | |
console.assert(err.message === 'testing111', 'Expected testing111'); | |
} | |
let w = yield('recovered'); | |
console.assert(w === 'recovered', 'Expected string recovered'); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
try { | |
let x = yield Promise.reject(new Error('testing111')); | |
} catch (err) { | |
console.assert(err.message === 'testing111', 'Expected testing111') | |
} | |
let w = yield('recovered'); | |
let z = yield w + '123'; | |
console.assert(z === 'recovered123', 'Expected string recovered123'); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
try { | |
let x = yield Promise.reject(new Error('testing111')); | |
} catch (err) { | |
console.assert( | |
err.message === 'testing111', 'Expected testing111' | |
); | |
} | |
let w = yield('recovered'); | |
let z = yield w + '123'; | |
console.assert(z === 'recovered123', 'Expected string recovered123'); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
try { | |
let x = yield Promise.reject(new Error('testing111')); | |
} catch (err) { | |
console.assert( | |
err.message === 'testing111', 'Expected testing111' | |
); | |
} | |
let w = yield('recovered'); | |
let z = yield w + '123'; | |
let xxx = yield Promise.resolve(z); | |
console.assert(xxx === 'recovered123', 'Expected string recovered123'); | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* () { | |
for (let i = 0; i < 10; i++) { | |
let r = yield fetch('/?test=' + i); | |
let text = r.text(); | |
} | |
return 'pass'; | |
})().then((r) => { | |
console.assert(r === 'pass', 'Expected pass') | |
}, err => console.assert(false, 'did not expect fail')); | |
async(function* (arg1) { | |
console.assert(arg1 === undefined, 'Argument 1 is undefined.') | |
return 'pass'; | |
})().then(expectedPass, expectedPass); | |
async(function* (arg1) { | |
console.assert(arg1 === 'pass', 'Argument 1 is pass.') | |
return 'pass'; | |
})('pass').then(expectedPass, expectedPass); | |
async(function* (arg1, arg2, arg3) { | |
console.assert(arg1 === 1, 'Argument 1 is 1.'); | |
console.assert(arg2 === 2, 'Argument 2 is 2.'); | |
console.assert(arg3 === 3, 'Argument 3 is 3.'); | |
console.assert(arguments.length === 3, 'Arguments length is 3.'); | |
return 'pass'; | |
})(1, 2, 3).then(expectedPass, expectedPass); | |
//non-async async | |
async(function(){ | |
return 'pass' | |
})().then(expectedPass, expectedPass); | |
async(function (arg1, arg2, arg3) { | |
console.assert(arg1 === 1, 'Argument 1 is 1.'); | |
console.assert(arg2 === 2, 'Argument 2 is 2.'); | |
console.assert(arg3 === 3, 'Argument 3 is 3.'); | |
console.assert(arguments.length === 3, 'Arguments length is 3.'); | |
return 'pass'; | |
})(1, 2, 3).then(expectedPass, expectedPass); | |
//bind tests | |
var obj = {value: '123', value2: 321} | |
async(function* (arg1) { | |
console.assert(this.value === '123', 'Bound `this.value` 123.'); | |
console.assert(this.value2 === 321, 'Bound `this.value2` 321.'); | |
return 'pass'; | |
},obj)().then(expectedPass, expectedPass); | |
async(function* (arg1, arg2, arg3) { | |
console.assert(this.value === '123', 'Bound `this.value` 123.'); | |
console.assert(this.value2 === 321, 'Bound `this.value2` 321.'); | |
console.assert(arg1 === 1, 'Argument 1 is 1.'); | |
console.assert(arg2 === 2, 'Argument 2 is 2.'); | |
console.assert(arg3 === 3, 'Argument 3 is 3.'); | |
console.assert(arguments.length === 3, 'Arguments length is 3.'); | |
return 'pass'; | |
}, obj)(1, 2, 3).then(expectedPass, expectedPass); | |
async(function (arg1) { | |
console.assert(this.value === '123', 'Bound `this.value` 123.'); | |
console.assert(this.value2 === 321, 'Bound `this.value2` 321.'); | |
return 'pass'; | |
},obj)().then(expectedPass, expectedPass); | |
async(function (arg1, arg2, arg3) { | |
console.assert(this.value === '123', 'Bound `this.value` 123.'); | |
console.assert(this.value2 === 321, 'Bound `this.value2` 321.'); | |
console.assert(arg1 === 1, 'Argument 1 is 1.'); | |
console.assert(arg2 === 2, 'Argument 2 is 2.'); | |
console.assert(arg3 === 3, 'Argument 3 is 3.'); | |
console.assert(arguments.length === 3, 'Arguments length is 3.'); | |
return 'pass'; | |
}, obj)(1, 2, 3).then(expectedPass, expectedPass); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment