知识共享许可协议

化解使用 Promise 时的竞态条件

原文:Defusing Race Conditions when Using Promises

网络时代,创建现代软件时其中一个很大的限制是所需要的数据往往在远程服务器上。应用程序在等待网络请求时简单地锁死是不现实(甚至不可能)的。相反,我们必须让应用程序在等待时保持响应。。

为此,我们需要写出并发的代码。当应用的某一部分正在等待网络请求的响应时,其他部分必须继续运行。 Promise 对于编写非阻塞型的代码是很不错的工具,而且你的浏览器就支持这个。

Promise 能让潜在可怕的异步代码变得非常友好。下面假设一个博客的文章视图这样从远程服务器加载一篇文章并显示它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Called from `componentWillMount` and `componentWillReceiveProps`:
ArticleView.prototype.updateArticle = function (props) {
this.setState({
error: null,
title: null,
body: null
});
ArticleStore.fetch(props.articleID).then(article => {
this.setState({
title: article.title,
body: article.body
});
}).catch(err => {
this.setState({ error: 'Oh Noes!' });
});
};

注意:这个例子使用了 React,但是这个概念适用于绝大多数前端视图系统。

这样的代码是很优雅的。许多复杂的异步调用消失了,取而代之的是直接明了的代码。然而,使用 promise 并不能保证代码是正确的。

注意到我例子中引入的不易察觉的竞态条件了吗?

提示:竞态条件出现的原因是无法保证异步操作的完成会按照他们开始时同样的顺序。

阅读全部

谈谈使用 promise 时候的一些反模式

本文翻译自 We have a problem with promises,为原文题目重新起了一个题目并且对原文有删改。

各位 JavaScript 程序员,是时候承认了,我们在使用 promise 的时候,会写出许多有问题的 promise 代码。 当然并不是 promise 本身的问题,A+ spec 规范定义的 promise 非常棒。 在过去的几年中,笔者看到了很多程序员在调用 PouchDB 或者其他 promise 化的 API 时遇到了很多困难。这让笔者认识到,在 JavaScript 程序员之中,只有少数人是真正理解了 promise 规范的。如果这个事实让你难以接受,那么思考一下我在 Twitter 上出的题:

问:下面四个使用 promise 的语句之间的不同点在哪儿?

1
2
3
4
5
6
7
8
9
10
11
doSomething().then(function () {
return doSomethingElse();
});
doSomethin().then(functiuoin () {
doSomethingElse();
});
doSomething().then(doSomethingElse());
doSomething().then(doSomethingElse);

如果你知道这个问题的答案,那么恭喜你,你已经是一个 promise 大师并且可以直接关闭这个网页了。

但是对于不能回答这个问题的程序员中 99.9% 的人,别担心,你们不是少数派。没有人能够在笔者的 tweet 上完全正确的回答这个问题,而且对于 #3 最终答案也令我感到震惊,即便我是出题人。

答案在本文的底部,但是首先,笔者必须先探究一下 promise 为何如此复杂,为什么不管是新手还是专家都有被 promise 折磨的经历。同时,笔者也会给出自认为能够快速、准确理解 promise 的方法。而且笔者确信读过这篇文章之后,理解 promise 不会那么难了。

在此之前,我们先了解一下有关 promise 的一些常识。

阅读全部