一次性解析 promise 单例(Angular 服务)
One-time resolving promise singleton (Angular service)
这个问题一般适用于承诺,并不特定于 Angular,但该示例使用了 Angular $q 和服务单例。
这里是a plunker
var app = angular.module('app', []);
app.factory('onetimeResolvingService', function ($q) {
var promise = $q(function(resolve, reject) {
setTimeout(function () {
resolve();
}, 500);
});
return promise;
});
app.controller('AController', function (onetimeResolvingService, $q) {
onetimeResolvingService.then(function () {
console.log('A resolved');
return $q.reject();
}).then(function () {
console.log('A resolved');
});
});
app.controller('BController', function (onetimeResolvingService, $q) {
onetimeResolvingService.then(function () {
console.log('B resolved');
return $q.reject();
}).then(function () {
console.log('B resolved');
});
});
文档是
<body ng-app="app">
<div ng-controller="AController"></div>
<div ng-controller="BController"></div>
</body>
自然会输出
A resolved
B resolved
什么是使单例承诺仅在第一次解析的好模式,即
A resolved
而不是以后的时间?
像 onetimeResolvingService.$$state.status = 2
这样的东西可能可以解决问题,但它看起来像 $q hack 并且闻起来很糟糕。
What would be a good pattern to make the singleton promise resolve only the first time
不要。承诺的一个关键方面是,一旦它被解决,它就被解决了,并且解决状态(解决或拒绝)和价值在那个时候都不会改变。参见 the A+ promises spec:
的 §2.1.2 和 §2.1.3
2.1.2 When fulfilled, a promise:
2.1.2.1 must not transition to any other state.
2.1.2.2 must have a value, which must not change.
2.1.3 When rejected, a promise:
2.1.3.1 must not transition to any other state.
2.1.3.2 must have a reason, which must not change.
如果通过 then
添加的回调在某个阶段不满足(例如,您的第二次连接),这不是一个承诺。是……别的东西。
T.J。 Crowder 是正确的,因为您在承诺中寻找的功能不存在。然而,如何实现您正在寻找的问题可以在如下结构中找到:
function OnetimeValue($q) {
var promisedValue = $q(function(resolve, reject) {
setTimeout(function () {resolve('The one time value');}, 500);
});
var valueGot = false;
this.GetValue = function GetValue() {
var res;
if (!valueGot) {
res = promisedValue;
} else {
res = $q(function(resolve, reject) {
resolve(null);
});
}
valueGot = true;
return res;
};
}
假设您 new
这一次(就像 angular 服务所做的那样),GetValue() 将在第一次调用时 return 承诺的字符串。后续调用 return null.
This plunker 显示上述内容
编辑:糟糕,看错问题了。
现在有一种方法可以使用 EcmaScript promises 来做到这一点。静态 Promise.resolve() 方法接受一个承诺并等待它的值;如果已经解决,它只是 returns 值。
例如,下面是我们如何使用此方法根据单个异步身份验证调用对 fetchQuery 进行多次调用:
fetchQuery 获取身份验证令牌 (JWT):
const authToken = await AuthToken.get();
AuthToken 看起来像 (TypeScript):
class AuthToken {
private static _accessTokenPromise: Promise<string>;
public static async get() {
if (!this._accessTokenPromise)
this._accessTokenPromise = this.AuthFunction(); // AuthFunction returns a promise
return await Promise.resolve(this._accessTokenPromise);
}
}
或者只需根据 OP 的问题对同一个 promise 对象调用 then() 两次,让两个调用等待同一个异步操作。
如果您使用 lodash
,您可以像这样简单地使用 memoize
:
const returnFirstRunResultAlways = _.memoize(async function(params) { ... })
这个问题一般适用于承诺,并不特定于 Angular,但该示例使用了 Angular $q 和服务单例。
这里是a plunker
var app = angular.module('app', []);
app.factory('onetimeResolvingService', function ($q) {
var promise = $q(function(resolve, reject) {
setTimeout(function () {
resolve();
}, 500);
});
return promise;
});
app.controller('AController', function (onetimeResolvingService, $q) {
onetimeResolvingService.then(function () {
console.log('A resolved');
return $q.reject();
}).then(function () {
console.log('A resolved');
});
});
app.controller('BController', function (onetimeResolvingService, $q) {
onetimeResolvingService.then(function () {
console.log('B resolved');
return $q.reject();
}).then(function () {
console.log('B resolved');
});
});
文档是
<body ng-app="app">
<div ng-controller="AController"></div>
<div ng-controller="BController"></div>
</body>
自然会输出
A resolved
B resolved
什么是使单例承诺仅在第一次解析的好模式,即
A resolved
而不是以后的时间?
像 onetimeResolvingService.$$state.status = 2
这样的东西可能可以解决问题,但它看起来像 $q hack 并且闻起来很糟糕。
What would be a good pattern to make the singleton promise resolve only the first time
不要。承诺的一个关键方面是,一旦它被解决,它就被解决了,并且解决状态(解决或拒绝)和价值在那个时候都不会改变。参见 the A+ promises spec:
的 §2.1.2 和 §2.1.32.1.2 When fulfilled, a promise:
2.1.2.1 must not transition to any other state.
2.1.2.2 must have a value, which must not change.
2.1.3 When rejected, a promise:
2.1.3.1 must not transition to any other state.
2.1.3.2 must have a reason, which must not change.
如果通过 then
添加的回调在某个阶段不满足(例如,您的第二次连接),这不是一个承诺。是……别的东西。
T.J。 Crowder 是正确的,因为您在承诺中寻找的功能不存在。然而,如何实现您正在寻找的问题可以在如下结构中找到:
function OnetimeValue($q) {
var promisedValue = $q(function(resolve, reject) {
setTimeout(function () {resolve('The one time value');}, 500);
});
var valueGot = false;
this.GetValue = function GetValue() {
var res;
if (!valueGot) {
res = promisedValue;
} else {
res = $q(function(resolve, reject) {
resolve(null);
});
}
valueGot = true;
return res;
};
}
假设您 new
这一次(就像 angular 服务所做的那样),GetValue() 将在第一次调用时 return 承诺的字符串。后续调用 return null.
This plunker 显示上述内容
编辑:糟糕,看错问题了。
现在有一种方法可以使用 EcmaScript promises 来做到这一点。静态 Promise.resolve() 方法接受一个承诺并等待它的值;如果已经解决,它只是 returns 值。
例如,下面是我们如何使用此方法根据单个异步身份验证调用对 fetchQuery 进行多次调用:
fetchQuery 获取身份验证令牌 (JWT):
const authToken = await AuthToken.get();
AuthToken 看起来像 (TypeScript):
class AuthToken {
private static _accessTokenPromise: Promise<string>;
public static async get() {
if (!this._accessTokenPromise)
this._accessTokenPromise = this.AuthFunction(); // AuthFunction returns a promise
return await Promise.resolve(this._accessTokenPromise);
}
}
或者只需根据 OP 的问题对同一个 promise 对象调用 then() 两次,让两个调用等待同一个异步操作。
如果您使用 lodash
,您可以像这样简单地使用 memoize
:
const returnFirstRunResultAlways = _.memoize(async function(params) { ... })