- 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/
如何从 promise 中退出 promise ? perl6 文档没有提供简单的方法。例如: my $x = start { loop { # loop forever until "qui
我的用户 Controller 中有一个索引操作,其中我试图连续做两件事,并且在它们都有机会完成之前不执行所需的 res.json() 方法。 我有一个加入用户的友谊加入模型。一列是 friender
请帮我解释一下为什么日志结果有两种不同: 方式 1:每 1 秒顺序记录一次 方式 2:1 秒后记录所有元素。 // Way 1 let sequence = Promise.resolve(); [1
我的问题很简单。 Promise.all() 方法可以返回 Promise 吗?让我解释一下: function simpleFunction() { let queue = [];
我正在使用 Promise 从存储中读取文件并转换为 base64 字符串。我有图像数组,使用 RNFS 读取图像 const promise_Images = _Images.map(async (
如果使用非空数组调用 Promise.all 或 Promise.race,它们将返回一个待处理的 Promise: console.log(Promise.all([1])); // prints
Promise.all 是否可以在没有包装 promise 的情况下返回链的最后一个值? 如果不使用 await,它在我的上下文中不起作用 没有包装的例子: function sum1(x){ r
我一直在玩 promise,通常能想出如何处理好它们,但在这种情况下,我不知道如何删除一个 promise-wrapping level。 代码如下: let promise2 = promise1.
考虑以下嵌套的Promises结构: const getData = async() => { const refs = [{ name: "John33", age: 3
我已经阅读了 Promise/A+ 规范,但据我了解,还有诸如 Promise/A 和 Promise 之类的东西。它们之间有什么区别? Promise 和 Promise/A 规范也是如此吗?如果是
当我运行以下代码时: my $timer = Promise.in(2); my $after = $timer.then({ say "2 seconds are over!"; 'result'
以下简单的 promise 是发誓的,我不允许打破它。 my $my_promise = start { loop {} # or sleep x; 'promise re
我正在尝试扩展Promise: class PersistedPromise extends Promise { } 然后在派生类上调用静态resolve以直接创建一个已解决的Promise: Per
我有两个返回 promise 的函数,我独立使用它们作为: getLocal().then(...) 和 getWeb().then(...) 但是现在我遇到了一个奇怪的问题: 1) 我需要第三个
我不知道 promise.all 解决方案中的 promise.all 是否是一个好的实践。我不确定。 我需要从一组用户获取信息,然后通过此信息响应,我需要发送消息通知。 let userList =
我一直在尝试使用 queueMicrotask() 函数,但我没有弄清楚当回调是微任务时回调的优先级如何。查看以下代码: function tasksAndMicroTasks() { const
我一直在尝试使用 queueMicrotask() 函数,但我没有弄清楚当回调是微任务时回调的优先级如何。查看以下代码: function tasksAndMicroTasks() { const
今年早些时候,我在 Pharo Smalltalk 参与了一个 promise 项目。这个想法是为了实现以下行为: ([ 30 seconds wait. 4 ]promiseValue )then:
大家好,提前感谢您的帮助。 下面是我正在尝试做的事情 function1(){ throw some error(); } function2() { // dosomething suc
我有以下未解析的代码。f2 解决了,所以我不会添加该代码,它是 f1 我有问题。 我调用函数,它到达最里面如果,它调用函数“find”,它执行函数 findId,完美返回 Id,然后执行 editId
我是一名优秀的程序员,十分优秀!