- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Promises/A+规范是最小的规范之一。因此,实现它是理解它的最佳方法。福布斯·林德赛(Forbes Lindesay)的以下回答将引导我们完成实现Promises / A +规范Basic Javascript promise implementation attempt的过程。但是,当我tested时,results并不令人满意:
✔ 109 tests passed
✘ 769 tests failed
最佳答案
什么是 promise ?
Promise是一个thenable
,其行为符合Promises/A+规范。thenable
是具有then
方法的任何对象或函数。
这是一个 promise 的样子:
var promise = {
...
then: function (onFulfilled, onRejected) { ... },
...
};
这是我们从一开始就了解的唯一 promise (不包括其行为)。
then
方法function deferred() { ... } // returns an object { promise, resolve, reject }
function fulfill(promise, value) { ... } // fulfills promise with value
function reject(promise, reason) { ... } // rejects promise with reason
尽管没有创建 promise 的标准方法,但是
tests仍然要求我们公开
deferred
函数。因此,我们将仅使用
deferred
创建新的Promise:
deferred()
:创建一个由{ promise, resolve, reject }
组成的对象:promise
是当前处于待处理状态的Promise。 resolve(value)
使用value
解决了 promise 。 reject(reason)
将 promise 从挂起状态转移到拒绝状态,拒绝原因为reason
。 deferred
函数的部分实现:
function deferred() {
var call = true;
var promise = {
then: undefined,
...
};
return {
promise: promise,
resolve: function (value) {
if (call) {
call = false;
resolve(promise, value);
}
},
reject: function (reason) {
if (call) {
call = false;
reject(promise, reason);
}
}
};
}
N.B.
promise
对象仅具有then
属性,当前为undefined
。我们仍然需要决定then
函数应该是什么以及promise对象应该具有哪些其他属性(即promise对象的形状)。该决定还将影响fulfill
和reject
函数的实现。 resolve(promise, value)
和reject(promise, value)
函数只能被调用一次,如果我们调用一个,那么我们就不能调用另一个。因此,我们将它们包装在一个闭包中,并确保它们之间仅被调用一次。 deferred
的定义中引入了一个新函数,即 promise 解决程序resolve(promise, value)
。规范将该函数表示为[[Resolve]](promise, x)
。该功能的实现完全由规范规定。因此,我们接下来将实现它。 function resolve(promise, x) {
// 2.3.1. If promise and x refer to the same object,
// reject promise with a TypeError as the reason.
if (x === promise) return reject(promise, new TypeError("Self resolve"));
// 2.3.4. If x is not an object or function, fulfill promise with x.
var type = typeof x;
if (type !== "object" && type !== "function" || x === null)
return fulfill(promise, x);
// 2.3.3.1. Let then be x.then.
// 2.3.3.2. If retrieving the property x.then results in a thrown exception e,
// reject promise with e as the reason.
try {
var then = x.then;
} catch (e) {
return reject(promise, e);
}
// 2.3.3.4. If then is not a function, fulfill promise with x.
if (typeof then !== "function") return fulfill(promise, x);
// 2.3.3.3. If then is a function, call it with x as this, first argument
// resolvePromise, and second argument rejectPromise, where:
// 2.3.3.3.1. If/when resolvePromise is called with a value y,
// run [[Resolve]](promise, y).
// 2.3.3.3.2. If/when rejectPromise is called with a reason r,
// reject promise with r.
// 2.3.3.3.3. If both resolvePromise and rejectPromise are called,
// or multiple calls to the same argument are made,
// the first call takes precedence, and any further calls are ignored.
// 2.3.3.3.4. If calling then throws an exception e,
// 2.3.3.3.4.1. If resolvePromise or rejectPromise have been called, ignore it.
// 2.3.3.3.4.2. Otherwise, reject promise with e as the reason.
promise = deferred(promise);
try {
then.call(x, promise.resolve, promise.reject);
} catch (e) {
promise.reject(e);
}
}
N.B.
promise = deferred(promise)
,使我们能够重用deferred
函数的逻辑。这样可以确保promise.resolve
和promise.reject
在两者之间只能调用一次。我们只需要对deferred
函数做些小改动就可以使该hack工作。 function deferred(promise) {
var call = true;
promise = promise || {
then: undefined,
...
};
return /* the same object as before */
}
promise 状态和
then
方法
fulfill
和
reject
函数的实现都依赖于它。现在该阅读规范对 promise 状态要说的内容了:
A promise must be in one of three states: pending, fulfilled, or rejected.
- When pending, a promise:
- may transition to either the fulfilled or rejected state.
- When fulfilled, a promise:
- must not transition to any other state.
- must have a value, which must not change.
- When rejected, a promise:
- must not transition to any other state.
- must have a reason, which must not change.
Here, “must not change” means immutable identity (i.e.
===
), but does not imply deep immutability.
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
var promise = {
then: function (onFulfilled, onRejected) { ... },
state: PENDING | FULFILLED | REJECTED, // vertical bar is not bitwise or
...
};
但是,还有更好的选择。由于 promise 状态只能通过其
then
方法观察到(即,根据 promise 状态,
then
方法的行为有所不同),我们可以创建与这三种状态相对应的三个专门的
then
函数:
var promise = {
then: pending | fulfilled | rejected,
...
};
function pending(onFulfilled, onRejected) { ... }
function fulfilled(onFulfilled, onRejected) { ... }
function rejected(onFulfilled, onRejected) { ... }
另外,我们还需要一个属性来保存 promise 的数据。当 promise 待定时,数据是
onFulfilled
和
onRejected
回调的队列。当 promise 兑现时,数据就是 promise 的值(value)。当 promise 被拒绝时,数据就是 promise 的原因。
deferred
函数的实现,如下所示:
function deferred(promise) {
var call = true;
promise = promise || {
then: pending,
data: []
};
return /* the same object as before */
}
另外,既然我们知道了promise对象的形状,那么我们终于可以实现
fulfill
和
reject
函数:
function fulfill(promise, value) {
setTimeout(send, 0, promise.data, "onFulfilled", value);
promise.then = fulfilled;
promise.data = value;
}
function reject(promise, reason) {
setTimeout(send, 0, promise.data, "onRejected", reason);
promise.then = rejected;
promise.data = reason;
}
function send(queue, callback, data) {
for (var item of queue) item[callback](data);
}
我们需要使用
setTimeout
,因为根据规范
section 2.2.4,在执行上下文堆栈仅包含平台代码之前,不得调用
onFulfilled
或
onRejected
。
pending
,
fulfilled
和
rejected
函数。我们将从
pending
函数开始,该函数将
onFulfilled
和
onRejected
回调推入队列并返回新的promise:
function pending(onFulfilled, onRejected) {
var future = deferred();
this.data.push({
onFulfilled: typeof onFulfilled === "function" ?
compose(future, onFulfilled) : future.resolve,
onRejected: typeof onRejected === "function" ?
compose(future, onRejected) : future.reject
});
return future.promise;
}
function compose(future, fun) {
return function (data) {
try {
future.resolve(fun(data));
} catch (reason) {
future.reject(reason);
}
};
}
我们需要测试
onFulfilled
和
onRejected
是否为函数,因为根据规范的
section 2.2.1,它们是可选参数。如果提供了
onFulfilled
和
onRejected
,则根据规范的
section 2.2.7.1和
section 2.2.7.2将它们与递延值组成。否则,它们会按照规范的
section 2.2.7.3和
section 2.2.7.4短路。
fulfilled
和
rejected
函数,如下所示:
function fulfilled(onFulfilled, onRejected) {
return bind(this, onFulfilled);
}
function rejected(onFulfilled, onRejected) {
return bind(this, onRejected);
}
function bind(promise, fun) {
if (typeof fun !== "function") return promise;
var future = deferred();
setTimeout(compose(future, fun), 0, promise.data);
return future.promise;
}
有趣的是,可以在上面恰当命名的
bind
函数中看到
promises are monads。至此,我们对Promises / A +规范的实现已完成。
resolve
规范的
Section 2.3.2描述了当
resolve(promise, x)
被确定为一个 promise 时对
x
函数的优化。这是优化的
resolve
函数:
function resolve(promise, x) {
if (x === promise) return reject(promise, new TypeError("Self resolve"));
var type = typeof x;
if (type !== "object" && type !== "function" || x === null)
return fulfill(promise, x);
try {
var then = x.then;
} catch (e) {
return reject(promise, e);
}
if (typeof then !== "function") return fulfill(promise, x);
// 2.3.2.1. If x is pending, promise must remain pending until x is
// fulfilled or rejected.
if (then === pending) return void x.data.push({
onFulfilled: function (value) {
fulfill(promise, value);
},
onRejected: function (reason) {
reject(promise, reason);
}
});
// 2.3.2.2. If/when x is fulfilled, fulfill promise with the same value.
if (then === fulfilled) return fulfill(promise, x.data);
// 2.3.2.3. If/when x is rejected, reject promise with the same reason.
if (then === rejected) return reject(promise, x.data);
promise = deferred(promise);
try {
then.call(x, promise.resolve, promise.reject);
} catch (e) {
promise.reject(e);
}
}
全部放在一起
$ npm install promises-aplus-tests -g
$ promises-aplus-tests promise.js
不用说,所有测试都通过了。
关于javascript - 了解Promises/A +规范,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36192728/
我们有一个 Java 项目,每天晚上使用 TeamCity 对 Java 类进行静态分析,以查找代码中容易出现的错误。我们想告诉 TeamCity 寻找开发人员可能引入的与 == 与 .equals
前言 🍊缘由 Git分支管理好,走到哪里都是宝 🏀事情起因: 最近翻看博客中小伙伴评论时,发现文章【规范】看看人家Git提交描述,那叫一个规矩一条回复: 本狗亲测在我司中使用规范
使用带有不存在的命名空间的命名空间限定关键字来定义规范是否被认为是不好的做法?我想在公共(public) domain 命名空间中定义实体映射...所以为了避免在合并规范时丢失数据,我使用约定 :en
有没有办法在调用 clojure.spec.test.alpha/check 时覆盖核心谓词函数的生成器? 可以通过 s/gen 中的路径覆盖谓词生成器: (gen/generate (s/gen
以内核 rpm 为例,它允许在一个系统上同时安装多个版本。规范文件中究竟是什么允许的? 我想打包一个已经存在的具有不同安装前缀的多个版本的项目。 最佳答案 百胜 找到了让 yum 安装而不是更新的方法
我正在尝试用 C# 编写 PDF 解析器,但我遇到了一个问题,我不确定如何解释规范。 除非另有说明,否则 PDF 文档中的用户空间为 1/72 英寸(即 1pt)。 Tf 运算符提供的比例将字体从标准
我正在编写一些代码,需要能够获取两个 pdf 并将它们附加到页面级别(例如,如果它们都是 2 页文档,则有一个 4 页文档,其中所有 4 页都与原始文档相同). 在不使用库的情况下,最好的方法是什么?
是否有序言语言语法,或接近它的通常用作引用的东西?我正在使用 SWI-prolog,所以有一个适合这种风格的会很好,否则一般的 prolog 语言语法/规范也能工作。 最佳答案 自 1995 年起,P
我需要一个函数来过滤参数和构建查询。我有 4 个参数,因此如果我尝试为每个条件实现查询,我将不得不写 16 (2^4)实现 - 这不是一个好主意。 我尝试使用界面改进我的代码 Specificatio
这个 ExtGState 对象对图像做了什么: > 我有 PDF 规范,但一点也不清楚。显然,这将身份函数(什么的身份?单位矩阵?)从 [0.0 1.0] 映射到 [0.0 1.0](相同),这是没有
只是想获得有关 ePub 规范的一些帮助。toc.ncx 是否必须具有 src(即 xhtml)。我观察到 .opf 文件中也提供了相同的内容 src。 最佳答案 是的,这是强制性的,这是一个设计问题
让我们看看莱宁根项目 map 的真实示例 :global-vars : ;; Sets the values of global vars within Clojure. This example
我正在开发一个 LOB 框架,它具有 SL 和 MVC 前端、WCF 后端以及在服务器上运行的几个服务模块。我一直在查看 Spec#,看它是否对我有任何帮助。不可空类型和检查异常本身非常好,但我还没有
Promises/A+规范是最小的规范之一。因此,实现它是理解它的最佳方法。福布斯·林德赛(Forbes Lindesay)的以下回答将引导我们完成实现Promises / A +规范Basic Ja
哪个文档指定了 MySQL definer 格式? 具体来说,definer admin@% 中的 % 是什么意思(以及为什么使用这个符号)? 最佳答案 这里MySQL使用的格式定义在the MySQ
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
在 css 规范中,什么会影响更多的 inline 样式或外部 !important 外部“style.css”: #di{color: green!important;} div 文本颜色是红色还
我正在努力思考 CSS 的一些细节,我从 W3 CSS Visual Formatting Spec 9.2.2 中找到了这部分摘录。特别迟钝: Inline-level boxes that are
这个问题在这里已经有了答案: Are (non-void) self-closing tags valid in HTML5? (8 个答案) 关闭 9 年前。 在 HTML5 中你应该使用 或
以下样式在规范方面有何不同? ul .active { background: #E7F3EF;} ul li.active { background: #E7F3EF;} Item 1
我是一名优秀的程序员,十分优秀!