TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

We have a problem with promises

164 点作者 nolanl大约 10 年前

22 条评论

falcolas大约 10 年前
Callback heavy languages can be very challenging to think about. They require keeping quite a few disparate pieces in your mental stack all at once.<p>Promises make this both better and worse, in my experience. In the easy cases, all you have to do is follow the promises syntax, and you can treat it as linear code.<p>The problem arises when writing non happy path code, you not only have to think about the promises syntax, but about the abstraction it&#x27;s creating over callbacks. Otherwise, you begin to miss corner cases, create incorrect promises, and in general write code which misbehaves (often silently).<p>Promises are powerful abstractions, but like all abstractions, they have their leaks. Also like all other abstractions, there are places where you have to fully comprehend the mechanisms underneath them to use them properly.
评论 #9564669 未加载
评论 #9564692 未加载
评论 #9565313 未加载
adrusi大约 10 年前
The real confusion here is dynamic typing. It&#x27;s weird that the parameter to .then() can return any value, but if it&#x27;s a promise there&#x27;s special behavior. And for no good reason either<p><pre><code> p.then(r =&gt; r + 5); </code></pre> Is just a bit of sugar for<p><pre><code> p.then(r =&gt; Promise.resolve(r + 5)); </code></pre> And then the type signatures are easy to reason about. The dynamic typing also risks introducing hard to find bugs. Suppose you have an heterogeneous array `things` which might contain numbers and promises which will resolve to numbers.<p><pre><code> p.then(r =&gt; things[r]) .then(thing =&gt; selectedThings.push(thing)); </code></pre> You might intend `selectedThings` to also contain either numbers or promises that resolve to numbers, ordered deterministically as a function of `p`, but instead it will contain only numbers and its order is nondeterministic (it depends on `p` and all of the promise members of `things` that `p` ever signals).
评论 #9565677 未加载
评论 #9565870 未加载
评论 #9566332 未加载
评论 #9565885 未加载
vkjv大约 10 年前
&gt; Rookie mistake #3: forgetting to add .catch()<p>I disagree with this advice. I usually refer to this as a &quot;Pokémon Catch&quot; (Gotta&#x27; Catch &#x27;Em All!). Never catch a promise that you are un-able to handle. It&#x27;s better to use a Promise library that supports debugging possibly unhandled exceptions (e.g., Bluebird).<p>&gt; Rookie mistake #4: using &quot;deferred&quot;<p>This one is interesting because it&#x27;s actually used in the Q library documentation for a way to `denodeify` or `promisify` a function. You definitely shouldn&#x27;t do this if it&#x27;s already a promise, but outside of that, it&#x27;s more of a gray area. I tend to recommend using libraries to convert callback functions to promises.
评论 #9565940 未加载
评论 #9565915 未加载
greggman大约 10 年前
I would argue that `Promise.all` is not the equivalent of `forEach` because Promise.all will execute everything immediately, maybe all will fail, maybe 1 will fail, eventually you&#x27;ll have your then or your catch called but 100 of your actions will have an attempt to be executed.<p>Compare that to forEach, if one fails and you throw the rest don&#x27;t get executed.<p>I suppose if whatever you&#x27;re doing for each thing is async then they are equivalent equivalent but in general forEach has different sementics than Promise.all
评论 #9565005 未加载
评论 #9564911 未加载
STRML大约 10 年前
Great article; a few things I would add. I use bluebird for Promises, which is just the most fantastic Promises lib ever conceived, no joke; if you haven&#x27;t used it try it. So some of these may be Bluebird-specific:<p>1. Don&#x27;t wrap callback functions manually with `new Promise(function(resolve, reject) {...})`, just use `Promise.promisify(...)`. For one-off functions, try `Promise.fromNode(function(cb) { fs.readFile(&#x27;..&#x27;, cb); });`.<p>2. This pattern:<p><pre><code> getUserByName(&#x27;nolan&#x27;).then(function (user) { return getUserAccountById(user.id); }).then(function (userAccount) { &#x2F;&#x2F; I got a user account! }); </code></pre> Could be:<p><pre><code> getUserByName(&#x27;nolan&#x27;) .get(&#x27;id&#x27;) .then(getUserAccountById) .then(function (userAccount) { &#x2F;&#x2F; I got a user account! }); </code></pre> 3. I too used Promise.resolve().then(...) to start a lot of route handlers. Try `Promise.try(function() {...})`, which is equivalent but reduces the temptation to just stick a synchronous value in the `Promise.resolve()` just because you can.<p>4. `Promise#nodeify()` is <i>super</i> useful for creating functions that return promises or use callbacks depending on how they&#x27;re called. For example:<p><pre><code> function getUserName(id, cb) { return db.getUserAsync(id).get(&#x27;name&#x27;) .nodeify(cb); } </code></pre> Is the same as:<p><pre><code> function getUserName(id, cb) { var promise = db.getUserAsync(id).get(&#x27;name&#x27;); if (!cb) return promise; promise.then(function(result) { cb(null, result);}) .catch(function(e) { cb(e); }); } </code></pre> This is great if you want to convert a few functions you use to promises, but they&#x27;re called elsewhere and expect a callback style.<p>I&#x27;m sure there are many more. This is my bible: <a href="https:&#x2F;&#x2F;github.com&#x2F;petkaantonov&#x2F;bluebird&#x2F;blob&#x2F;master&#x2F;API.md" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;petkaantonov&#x2F;bluebird&#x2F;blob&#x2F;master&#x2F;API.md</a><p>In short; use Promises! They are the answer for callback hell in Node. Async&#x2F;await may fix more problems in the future but if you want Node&#x2F;Browser compatibility and to get started right now, Promises are the best way to go.
评论 #9564946 未加载
评论 #9564693 未加载
评论 #9565608 未加载
davexunit大约 10 年前
The messes that callback&#x2F;promise-heavy JavaScript make are a good example of why we need syntactic abstraction in the language. With a proper macro system, this whole async mess could be abstracted away and we could write nice linear code.
评论 #9564876 未加载
评论 #9565926 未加载
johnnymonster大约 10 年前
its interesting that when people talk about the newest feature or framework in javascript, they tend to forget about javascript&#x27;s core functionality. It&#x27;s always necessary to look at things like promises with javascript&#x27;s core functionality in mind. Take #3 for example, which is really just a function of the core way javascript executes, taking promises aside!<p>You would not do something like this would you in a normal day at the office? function myFunction(doSomething()){<p>};<p>so why would you do this.<p>Promise.then(doSomething());<p>doSomething() gets immediately invoked when the code is evaluated. It has nothing to do with Promises.<p>Don&#x27;t forget the fundamentals!
评论 #9565302 未加载
评论 #9565806 未加载
LordHumungous大约 10 年前
&gt;If you know the answer, then congratulations: you&#x27;re a promises ninja<p>No... you know how functions work in javascript.
评论 #9565600 未加载
评论 #9565202 未加载
评论 #9565281 未加载
xtrumanx大约 10 年前
What&#x27;s so bad about using deferred? In one case I call the resolve or reject parameters and in the other I call a resolve or reject properties on the deferred object. Not much of a difference to me.<p>I learned about deferred a few years ago and kinda stuck with it. It&#x27;s all over my code base and he didn&#x27;t really justify why I should go about changing it. The only thing I can reason I can think of is using his recommendation follows the ES6 spec which doesn&#x27;t matter to me that much for now.
评论 #9564910 未加载
评论 #9565365 未加载
评论 #9565156 未加载
tel大约 10 年前
Re &quot;Advanced Mistake #4&quot;, do Javascript programmers not know about tuples? Does nobody write functions with signatures like<p><pre><code> pair(pa: Promise&lt;A&gt;, pb: (a: A) =&gt; Promise&lt;B&gt;): Promise&lt;{fst: A, snd: B}&gt; { return pa.then(function (a) { return pb(a).map(function (b) { return {fst: a, snd: b} }) }) } </code></pre> It&#x27;s a super reusable little chunk of code.
评论 #9566022 未加载
nolanl大约 10 年前
If anyone&#x27;s confused by the 4 &quot;puzzles,&quot; I whipped up a JSBin to demonstrate: <a href="http:&#x2F;&#x2F;jsbin.com&#x2F;tuqukakawo&#x2F;1&#x2F;edit?js,console,output" rel="nofollow">http:&#x2F;&#x2F;jsbin.com&#x2F;tuqukakawo&#x2F;1&#x2F;edit?js,console,output</a>
评论 #9565037 未加载
arxpoetica大约 10 年前
I made the transition from callbacks to generators&#x2F;iterators recently, and I&#x27;m really enjoying the yield&#x2F;next foo. Promises just never really spoke to me. Not certain why I always felt reticent to use them.
评论 #9564907 未加载
embwbam大约 10 年前
Typescript or Flow will catch many of these errors. Highly recommended!
评论 #9565003 未加载
评论 #9564901 未加载
tel大约 10 年前
And this is why types are nice. Along with limited overloading.
neumino大约 10 年前
Gosh, adding a `.catch(console.log.bind(console))` is just insane.<p>If you have a library that will return non operational error, just remove it from your project. If your code throws when it is not expected to, fix it.<p>This is like saying put a `try&#x2F;catch(ignore)` everywhere. Seriously.
评论 #9565477 未加载
评论 #9566149 未加载
评论 #9565942 未加载
mweibel大约 10 年前
Very nice article, will keep that in mind when trying to help others with promises. Also helped me to re-understand some things :)<p>One thing though, Advanced mistake #4, is in my opinion good answer, the Q library however gives a (afaik) non-a+-standard way of doing that which I like:<p>from:<p><pre><code> getUserByName(&#x27;nolan&#x27;).then(function (user) { return getUserAccountById(user.id); }).then(function (userAccount) { &#x2F;&#x2F; dangit, I need the &quot;user&quot; object too! }); </code></pre> to:<p><pre><code> getUserByName(&#x27;nolan&#x27;).then(function (user) { return [user, getUserAccountById(user.id)]; }).spread(function (user, userAccount) { &#x2F;&#x2F; I do have the user object here });</code></pre>
tumbling_stone大约 10 年前
The most comprehensive and foolproof way is to grab the spec, read the algorithm and fiddle around a day. Sadly this is the only way of fully understand promises, promises already put a lot of cognitive load on your brain when you&#x27;re using them, so having any other abstractions of your own (for remembering how promises work) is bad idea. IMO you&#x27;re better off investing a large continuous block of time for understanding promises rather than reading some article here and there.
janfoeh大约 10 年前
I am stumbling over this:<p>&gt; Just remember: any code that might throw synchronously is a good candidate for a nearly-impossible-to-debug swallowed error somewhere down the line.<p>Why would a synchronously thrown error be swallowed, and why would I not just `try { } catch` here?
评论 #9564866 未加载
ThrustVectoring大约 10 年前
Puzzle number 3 doesn&#x27;t have a complete explanation. DoSomethingElse() can return a function, which is then evaluated with the result of the first promise as an argument.
tlrobinson大约 10 年前
As soon as you can reasonably introduce an ES6&#x2F;7 transpiler into your toolchain you should start using ES7&#x27;s async&#x2F;await or equivalently ES6&#x27;s generators + a coroutine library function like Bluebird.coroutine, Q.async, co, or Task.js.<p>It solves basically all of the problems mentioned in this article.
adhambadr大约 10 年前
hahahahaha this one cracked me up &quot;Writing code without a stack is a lot like driving a car without a brake pedal: you don&#x27;t realize how badly you need it, until you reach for it and it&#x27;s not there.&quot;
评论 #9564867 未加载
评论 #9566564 未加载
jjaredsimpson大约 10 年前
If devs don&#x27;t want to read specs and instead read blog posts then its obvious why there is a problem.
评论 #9565086 未加载