ysmood / yaku Goto Github PK
View Code? Open in Web Editor NEWA lightweight promise library
Home Page: https://tonicdev.com/ysmood/yaku
License: MIT License
A lightweight promise library
Home Page: https://tonicdev.com/ysmood/yaku
License: MIT License
The following code is not working in UC Browser, because this
is undefined inside an IIFE in UC Browser.
function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {var Yaku = __webpack_require__(/*! ./yaku */ 80);
try {
global.Promise = Yaku;
window.Promise = Yaku;
} catch (err) {
null;
}
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ }
It's desirable for me to have Promise.any. (i.e. If any promise resolves, then resolve).
Is it possible to create this method using the existing methods in Yaku? (e.g. I could do something similar to https://github.com/andyjansson/promise-any/blob/master/index.js ).
Is this a good idea? or should I wait for this functionality to appear in Yaku?
I have a case, when I need pass callback to unhandledRejection handler and can't use catch in default maner, when I try define property for the promise, I notice that property do not passed in promise at onUnhandledRejection, how I can implement this behaviour?
Example:
const onUnhandledRejection = (reason, promise) => {
// promise.handleRejection always undefined
if (promise && typeof promise.handleRejection === 'function') {
promise.handleRejection(reason);
} else {
console.error(reason);
}
};
window.onunhandledrejection = ({ reason, promise }) => {
onUnhandledRejection(reason, promise);
};
const handleRejection = (promise) => {
Object.defineProperty(promise, 'handleRejection', {
enumerable: false,
configurable: false,
writable: false,
value: (reason) => {
if (reason && reason instanceof SkipError) return;
console.error('MIDDLEWARE ERROR:', reason, reason.stack);
// ...customize global rejection handler for this promise
}
});
return promise;
};
handleRejection(promise(client)).then(
(result) => {
// ...
},
(error) => {
throw SkipError;
}
);
When do we consider adding finally
to yaku
?
https://github.com/tc39/proposal-promise-finally
From yaku
readme:
- Will Yaku implement done, finally, etc?
No. All non-ES6 APIs are only implemented for debugging and testing, which means when you remove Yaku, everything should work well with ES6 native promise.
Such as the src/guard.js
doesn't work with old IEs.
Hey, can you run @spion's benchmarks that simulate a real server async workload and report the results?
Here it is: https://github.com/petkaantonov/bluebird/tree/master/benchmark
Cheers.
A must have feature.
I think the documentation for .async
is very misleading since it says:
An throttled version of
Promise.all
A lot of people, in my experience answering questions in StackOverflow, being involved in the spec process and helping maintain a library is that a lot of people mix up the fact a promise is a proxy for the value of an already started operation.
A throttled Promise.all
is impossible of course since all the inputs to .all
are already promises which means the operations themselves have already started.
It would be useful to update the documentation to reflect that, also it would be nice if the docs were moved to an API.md
file or something similar.
Hi,
We use Yaku for production and had a need for a mock mode to allow synchronous tests.
I hacked it in:
https://github.com/lukeapage/yaku-mock
If I cleaned it up, abstracted and made a PR back to you, would you be interested? or should I keep it as a fork?
If we call a promise's then
method multiple times, it may potentially cause memory leak:
var p = Promise.resolve();
p.then(function () {});
p.then(function () {});
p.then(function () {});
p.then(function () {});
p.then(function () {});
process.on('exit', () => {
p = null;
});
If we don't release variable p
, its children promises will stay in memory even after p
and all the children are settled. What we should do with this situation is not specified in the ES6 yet.
I think we should cut off the link between the parent and child immediately after the child is settled.
If I call finally
on a rejected promise it unexpectedly becomes fulfilled.
const Promise = require(process.argv[2]);
const p = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('simulated error')));
});
p.finally(() => {
console.log('Cleanup');
})
.then(result => {
console.log('Unexpected success', result);
})
.catch(err => {
console.error('Expected failure', err);
});
With yaku:
$ node index.js yaku
Cleanup
Unexpected success Error: simulated error
With bluebird:
$ node index.js bluebird
Cleanup
Expected failure Error: simulated error
Your finally
test doesn't catch this because although you expect 'error'
here: https://github.com/ysmood/yaku/blob/master/test/finally.js#L28
You do not confirm that its a rejection here: https://github.com/ysmood/yaku/blob/master/test/testSuit.js#L14
The cause is that you do not rethrow or wrap value
with Promise.reject
here:
Line 154 in b5187ec
retry
won't work when build with babel async await
This would enable the library to be used as a pure polyfill. What do you think to the idea?
Bluebird provides the Promise.setScheduler method to bind with the angular digest cycle.
// This will synchronize bluebird promise queue flushing with angulars queue flushing
// Angular is also now responsible for choosing the actual scheduler
Promise.setScheduler(function(fn) {
$rootScope.$evalAsync(fn);
});
Can the same thing be achieved with Yaku?
check out the test case here: https://gist.github.com/kdepp/1d58214e989c9d4166f4
Both with the longStackTrace option on, bluebird gives me the exact exception point and all other calls when promises are resolved, while yaku only prints out the outmost 'then' and other useless function call.
Any thoughts on this?
Reproduction:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="path/to/yaku.browser.full.min.js"></script>
<script>
console.log(Yaku.all);
</script>
</body>
</html>
Yaku.all
expect is Promise.all
but actually is yaku.util.all
https://github.com/ysmood/yaku/blob/master/src/browser.full.js#L8
Such as
var utils = require('yaku/lib/utils');
var f = fs.createReadStream('test');
var p = utils.promisify(f);
p.then(function (data) {
console.log(data);
})
Expected:
> Object.getOwnPropertyDescriptor(global,'Promise');
{ value: [Function: Promise],
writable: true,
enumerable: false,
configurable: true }
> global.Promise.name
'Promise'
Actual:
> Object.getOwnPropertyDescriptor(global,'Promise');
{ value:
{ [Function]
default: [Circular],
resolve: [Function],
reject: [Function],
race: [Function],
all: [Function],
Symbol: [Function: Symbol],
speciesConstructor: [Function],
unhandledRejection: [Function],
rejectionHandled: [Function: en],
enableLongStackTrace: [Function],
nextTick: [Function: nextTick],
_s: 1 },
writable: true,
enumerable: true,
configurable: true }
> global.Promise.name
''
var Promise = require("yaku");
var assert = require('assert');
var stolenResolver;
var StealingPromiseConstructor = function StealingPromiseConstructor(resolver) {
stolenResolver = resolver;
resolver(
function () {},
function () {}
);
};
var iterable = {};
var atAtIterator = '@@iterator'; // on firefox, at least.
iterable[atAtIterator] = function () {
stolenResolver(null, null);
throw new Error(0);
};
assert.doesNotThrow(function () {
Promise.all.call(StealingPromiseConstructor, iterable);
});
It throws this:
AssertionError: Got unwanted exception.
Actual message: "self.reject is not a function"
This test was taken from es6-shim -- https://github.com/paulmillr/es6-shim/blob/4a815033b35a051632e035e1ec95aa3b1b43bfdd/test/promise/simple.js#L34-L51
It will decrease the code base a little, and make it more friendly for beginners.
Your package.json declares ./lib & ./dist which doesn't exists (anymore ?) ;)
This is the weirdest glitch I've found in my entire existence.
If you add a <div id="process">
to the DOM, it breaks.
The problem is that Yaku checks for window.process
, which seems to be defined in some browsers as $("#process")
. Yaku then tries to use process.nextTick
, which of course doesn't exist.
This doesn't happen in all browsers; not sure why.
Here is an edge case bug that we found in our production code. In the new Promise()
constructor, if the resolve callback is called twice with another promise, then the second call to resolve
overwrites the first call. A simple test case:
//comment out this line to test native version
const Promise = require('yaku');
const firstValue = Promise.resolve('correct');
const testPromise = new Promise(resolve => {
resolve(firstValue); //first resolve another promise
resolve('wrong'); //then resolve a value
});
//this line should log `correct`, but logs `wrong`
testPromise.then(x => console.log(x));
This only seems to happen when firstValue
is a promise, when it's just the string 'correct'
the code works the same as the native Promise implementation.
As I said at the beginning, this is an edge case bug, as calling resolve
multiple times is not good, but we had an issue with this in production (we use polyfill.io for IE11 support), so I thought I'd at least let you know of the issue.
Hey, the docs say that the library does not offer things like .done
, but it appears it just exposes a (differently named) .end
instead.
I warmly recommend the following:
.defer
, deferreds are super problematic anyway, they were decided against in the official API for the Zalgo problem they cause..end
, you have unhandled rejection detection already - that's better anyway..isPromise
, that encourages (in my experience) users to rely on it instead of Promise.resolve
ing results.source
to another unrelated repo, it is practically a mini observable. It's worth documenting separately.This prints done
as expected:
callbackify(function() {
return Y.resolve('a');
})(1, function() {
return console.log('done');
});
while this does not:
callbackify(function() {
return Y.resolve('a');
})(function() {
return console.log('done');
});
The only difference is the first example passes an extra (unused) argument to the function returned by callbackify.
I'm using promise.prototype.finally
to add the finally
functionaity to Promises, but that depends on the promise's constructor
to be Promise
. Currently the constructor is Object
.
> (new Promise(function() {})).constructor
Object() { [native code] }
This would enable people to use npmcdn.com/yaku
in their webpages which don't have a build-step.
You use Error#stack
quite a bit in the code which was only supported by IE10+
https://github.com/ysmood/yaku/blob/master/src/yaku.coffee#L231
Change that line to return if not isObject root.console
When I use catch
or the second argument of then
to handle a rejection, Unhandled Rejection
is always shown.
yaku = require 'yaku'
new yaku (resolve, reject) ->
reject 1
.catch ->
the result is
Unhandled Rejection: 1
I think this bug is introduced in v0.2.0
console.trace is not a good enough way to show stack trace. Also, uglified code make it pretty difficult to debug.
Unhandled rejection Error: [TypeError: Cannot read property 'value' of undefined]
Trace
at Function.t.onUnhandledRejection (/usr/local/lib/node_modules/nokit/node_modules/nofs/node_modules/yaku/dist/yaku.js:6:822)
at /usr/local/lib/node_modules/nokit/node_modules/nofs/node_modules/yaku/dist/yaku.js:6:2168
at r (/usr/local/lib/node_modules/nokit/node_modules/nofs/node_modules/yaku/dist/yaku.js:6:1171)
at process._tickCallback (node.js:442:13)
If i do something like this as a polyfill:
window.Promise = require('yaku');
Then the recent change in 0.18.3 is broken: 950101f
Shouldn't you capture window.Promise
outside of the function in case it gets overridden?
See my comments in 0383fa0
Hello hello
First things first, i like your library โค๏ธ ๐ , it provides huge benefits compared to other promraries (promise-libraries ๐)! Mainly its size is a really killer feature! But the longStackTraces are a good thing too.
But now I found a very strange problem: As soon as I use Yaku with rollup or brunch (yes I tried both), I notice a very long wait time from resolve
to then
. It is loading and loading, while a bluebird promise which was started in the same time as yaku, already has resolved.
(When I try yaku promises after the page is fully loaded, it works without problems, this slow resolve only happens on pageload)
Do you have an idea?
This is the code:
Yaku.resolve().then(function() {
console.log('yaku1')
})
Yaku.resolve().then(function() {
console.log('yaku2')
})
bluebird.resolve().then(function() {
console.log('bluebird')
})
One thing I noticed too is, that when I console.log(Yaku)
this log takes the same time to complete as the Yaku resolves! It is very strange: first the log just outputs function
, and then it magical changes the function
to:
function Promise(executor) {
var self = this,
err;
// "this._s" is the internal state of: pending, resolved or rejected
// "this._v" is the internal value
โฆ
This is the rollup config I used:
var flow = require('rollup-plugin-flow');
import babel from 'rollup-plugin-babel';
var serve = require('rollup-plugin-serve')
var path = require('path')
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
export default {
entry: 'app/main.js',
dest: 'app/assets/bundle.js',
plugins: [ flow(), nodeResolve({
jsnext: true, main: true
}), commonjs(), serve({
contentBase: path.join(__dirname, 'app', 'assets')
}) ],
format: 'umd'
};
Are there any benchmarks which say what the trade-off is with using long stack traces?
Thanks
I can track down further if its not obvious but I've been trying to work out why I get unhandled rejections for promises that are handled. I've not been able to make a reduced test case, but the behaviour seems to occur when I have something like
promise.catch(() => {
// maybe do something different
return Promise.reject({});
}).catch(() => {
// absorb rejection so unhandledrejection should not be called
});
and it appears changing the return to throw make it work and not give unhandled rejections (which is the expected behaviour).
Hey, if you want node usage, it would be immensely useful to support promisify
natively. Without the library supporting it itself, it is impossible to make promisify
comparably fast.
See bluebird's https://github.com/petkaantonov/bluebird/blob/master/src/promisify.js for inspiration :)
I saw you already have a promisify.js file, but it is slow (uses a closure and .slice
).
A promisifyAll
would also be immensely useful for server side use.
Basically https://gist.github.com/benjamingr/0237932cee84712951a2
Most promise libraries and native promises in NodeJS support the global rejection events, these events in NodeJS allow code using multiple promise libraries and native promises in the same project to handle rejecitons globally and uniformally throughout the application and to provide a useful hook.
It also makes switching libraries simpler.
It would be great if Yaku could support it, I don't mind writing the PR but I think that you already know how to :)
This issue is inspired by the exercise, as described in the test case of this exercise, when the throttled-promise handler get all it's tasks done, the saveResults
should keep their order as they are the result of each one of list
async: (limit, list, saveResults, progress) ->
...
Also, I modify one existed test case of yours, to show the difference.
test 'async array', [1, 2, 3], ->
list = [
-> utils.sleep 90, 1
-> utils.sleep 10, 2
-> utils.sleep 10, 3
]
utils.async 2, list
The old version will get [2, 3, 1]
instead of [1, 2, 3]
.
And there is a pull request. I hope myself get this right.
Per https://github.com/ysmood/yaku/blob/master/docs/debugHelperComparison.md#better-unhandled-error, Yaku will not fire an unhandledrejection
event in this case:
p0 = Yaku.resolve().then(function () {
abc()
})
p1 = p0.then(function () {})
p2 = p0.then(function () {})
p3 = p0.catch(function () {})
From my understanding, this is incorrect behavior. p1
and p2
are new promises that have unhandled rejections.
I think the following should happen:
window.onunhandledrejection = ({promise}) => {
console.log('window.onunhandledrejection: p' + promises.indexOf(promise));
}
p0 = Yaku.resolve().then(function () {
abc()
})
p1 = p0.then(function () {})
p2 = p0.then(function () {})
p3 = p0.catch(function () {})
promises = [p0, p1, p2, p3]
// should log 'unhandledrejection: p1'
// should log 'unhandledrejection: p2'
I believe Chrome actually implements the spec correctly.
hello,
thank you for the nice library I am currently using http://polyfill.io which uses this as polyfill for Promise
, but there is no support for Promise.allSetteled
can you please consider this ?
-Thank you
I'm sure you know, but it's a proposal http://2ality.com/2017/08/promise-try.html and is already integrated in other Promise libs (ex. bluebird)
Would be nice to have!
model ----> observableA ----> view
^ |
โ-------- observableB -------โ
As title ๐
Promise.reject(10).then(->)
It will log the error info twice.
i try to add a handler for all unhandled rejection:
window.onunhandledrejection = ({ reason, promise }) => { console.log('help');};
Promise.reject(new Error("ERR"));
The only output i can see is the default 'Potentially unhandled rejection [1] Error: ERR'.
Is it a bug or am i using it wrong?
Could we add a hash helper like the RSVP
, I think it's very convenient and useful? You think that is OK with you? Maybe I could implement it myself and make a PR.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.