javascript Promise API 是否比需要的更复杂?
Is javascript Promise API more convoluted than it needs to be?
我想在大多数情况下,我终于设法围绕 javascript/ES6 承诺进行了思考。这并不容易!但是有一些让我困惑的设计。
为什么 Promise 构造函数需要回调?鉴于回调是立即调用的,调用者是否可以直接执行该代码,从而避免一种不必要的令人费解的程度"don't call me, I'll call you"?
以下是我认为的 Promise 用法的原型示例,复制自 Jake Archibald 的 Javascript Promises 教程 http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest,删除了注释。
它是 XMLHttpRequest GET 请求的基于 Promise 的包装器:
function get(url) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
}
else {
reject(Error(req.statusText));
}
};
req.onerror = function() {
reject(Error("Network Error"));
};
req.send();
});
}
对我来说,如果将上面的代码重写如下,使用我想象中的一种非常不同的承诺,具有无参数构造函数和 resolve/reject,那么上面的代码会更容易理解方法:
function get(url) {
var promise = new MyEasierToUnderstandPromise();
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
if (req.status == 200) {
promise.resolve(req.response);
}
else {
promise.reject(Error(req.statusText));
}
};
req.onerror = function() {
promise.reject(Error("Network Error"));
};
req.send();
return promise;
}
MyEasierToUnderstandPromise 在 Promise 方面并不难实现。起初我试着让它成为 Promise 的实际子类,但出于某种原因我无法让它工作;所以我将它实现为一个简单的工厂函数,returns 一个带有几个额外函数的普通旧 Promise 对象
附加的行为类似于成员函数:
function NewMyEasierToUnderstandPromise() {
var resolveVar;
var rejectVar;
var promise = new Promise(function(resolveParam, rejectParam) {
resolveVar = resolveParam;
rejectVar = rejectParam;
});
promise.resolve = resolveVar;
promise.reject = rejectVar;
return promise;
};
那么,为什么 Promise 不是这样设计的呢?我想如果是的话,它会帮助我更快地理解 Promises——我打赌它会把我的学习时间减半。
我知道很多聪明人都参与了 Promise API,每个人似乎都为此感到高兴和自豪,所以我想知道他们在想什么。
您的版本不是异常安全的,而 Promises/A+ 是安全的,因为它们被 Promise
构造函数捕获。
作为辅助信息,当脚本定义 ES6 promise 链时
var promise = new Promise(executor).then(something).catch(handleError);
promise 变量保留为 .catch 方法调用返回的 promise。执行器函数持有的 resolve/reject 函数引用实际上阻止了整个链或 Promise 对象被垃圾收集。如果 resolve 被调用(通常在执行器 returns 之后异步但在让 resolve/reject 函数超出范围之前),then
侦听器 "something" 被调用,内部有一个 Promise 平台执行者为 then
调用返回的 promise 持有 resolve/reject 函数引用,以防止它和任何后续链式 promise 本身被过早地垃圾收集。
在延迟模型下,建议您不能以这种方式设置承诺链,因为您需要引用链中的 first 承诺才能解决或拒绝它。代码变得更像
var promise = new Promise(); // no executor
promise.then(something).catch(handleError);
initiateOperation( promise);
然后在操作响应码中异步
promise.resolve(value); // if no error occurred
promise = null; // explicit discard of first promise reference to allow GC?
ES6 承诺的一般简约方法现在开始看起来很有希望(哎哟)。我很同情你在学习 promises 是如何工作时遇到的困难 - 一个有趣的旅程!!!
承诺旨在用作值。 ES 构造函数方法封装了 Promise 的创建,然后可以像值一样传递它。当传递该值时,该值的使用者不需要 resolve
和 reject
,因此这些函数不应该是 public API.[= 的一部分12=]
(以及关于异常处理和链接的所有内容)
我想在大多数情况下,我终于设法围绕 javascript/ES6 承诺进行了思考。这并不容易!但是有一些让我困惑的设计。
为什么 Promise 构造函数需要回调?鉴于回调是立即调用的,调用者是否可以直接执行该代码,从而避免一种不必要的令人费解的程度"don't call me, I'll call you"?
以下是我认为的 Promise 用法的原型示例,复制自 Jake Archibald 的 Javascript Promises 教程 http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest,删除了注释。
它是 XMLHttpRequest GET 请求的基于 Promise 的包装器:
function get(url) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
}
else {
reject(Error(req.statusText));
}
};
req.onerror = function() {
reject(Error("Network Error"));
};
req.send();
});
}
对我来说,如果将上面的代码重写如下,使用我想象中的一种非常不同的承诺,具有无参数构造函数和 resolve/reject,那么上面的代码会更容易理解方法:
function get(url) {
var promise = new MyEasierToUnderstandPromise();
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
if (req.status == 200) {
promise.resolve(req.response);
}
else {
promise.reject(Error(req.statusText));
}
};
req.onerror = function() {
promise.reject(Error("Network Error"));
};
req.send();
return promise;
}
MyEasierToUnderstandPromise 在 Promise 方面并不难实现。起初我试着让它成为 Promise 的实际子类,但出于某种原因我无法让它工作;所以我将它实现为一个简单的工厂函数,returns 一个带有几个额外函数的普通旧 Promise 对象 附加的行为类似于成员函数:
function NewMyEasierToUnderstandPromise() {
var resolveVar;
var rejectVar;
var promise = new Promise(function(resolveParam, rejectParam) {
resolveVar = resolveParam;
rejectVar = rejectParam;
});
promise.resolve = resolveVar;
promise.reject = rejectVar;
return promise;
};
那么,为什么 Promise 不是这样设计的呢?我想如果是的话,它会帮助我更快地理解 Promises——我打赌它会把我的学习时间减半。
我知道很多聪明人都参与了 Promise API,每个人似乎都为此感到高兴和自豪,所以我想知道他们在想什么。
您的版本不是异常安全的,而 Promises/A+ 是安全的,因为它们被 Promise
构造函数捕获。
作为辅助信息,当脚本定义 ES6 promise 链时
var promise = new Promise(executor).then(something).catch(handleError);
promise 变量保留为 .catch 方法调用返回的 promise。执行器函数持有的 resolve/reject 函数引用实际上阻止了整个链或 Promise 对象被垃圾收集。如果 resolve 被调用(通常在执行器 returns 之后异步但在让 resolve/reject 函数超出范围之前),then
侦听器 "something" 被调用,内部有一个 Promise 平台执行者为 then
调用返回的 promise 持有 resolve/reject 函数引用,以防止它和任何后续链式 promise 本身被过早地垃圾收集。
在延迟模型下,建议您不能以这种方式设置承诺链,因为您需要引用链中的 first 承诺才能解决或拒绝它。代码变得更像
var promise = new Promise(); // no executor
promise.then(something).catch(handleError);
initiateOperation( promise);
然后在操作响应码中异步
promise.resolve(value); // if no error occurred
promise = null; // explicit discard of first promise reference to allow GC?
ES6 承诺的一般简约方法现在开始看起来很有希望(哎哟)。我很同情你在学习 promises 是如何工作时遇到的困难 - 一个有趣的旅程!!!
承诺旨在用作值。 ES 构造函数方法封装了 Promise 的创建,然后可以像值一样传递它。当传递该值时,该值的使用者不需要 resolve
和 reject
,因此这些函数不应该是 public API.[= 的一部分12=]
(以及关于异常处理和链接的所有内容)