我正在为keepassxc网络扩展构建抽象层。它使用redux-saga通道来使chrome消息传递看起来是同步的。它运行得出奇地好。不过,我想要完全抽象化还原-传奇,它的方式将看起来像正常的函数返回承诺。
tl;博士
KeePassXC浏览器将是浏览器扩展,允许从浏览器检索存储在KeePassXC应用程序中的密码。有两种可能的通信协议: HTTP和NativeClient。因此,我决定使用类型记录接口,根据通信协议的不同,将有两个类实现这个接口。
接口:
interface Keepass {
getDatabaseHash(): Promise<string>;
getCredentials(origin: string, formUrl: string): Promise<KeepassCredentials[]>;
associate(): Promise<KeepassAssociation>;
isAssociated(dbHash: string): Promise<boolean>;
}首次实施表示HTTP通信协议使用的是基于承诺的取api,因此实现是直截了当的,并且100%符合这个接口。
第二次实施表示NativeClient协议是使用redux(效果和通道)使异步消息传递看起来像同步函数调用。这是有点复杂,但工作相当好,涵盖边缘情况,这将很难处理任何其他方式,因为本地消息传递是基于标准输入和标准输出流的协议,所以请求和响应可以交织,无序等……
我没有解决的实际问题是,第二个实现没有实现接口,因为它的生成器没有承诺。
主要想转换(包装)传奇迭代器功能和功能返回承诺。有一个很好的co库,基本上是为普通的生成器这样做的。但似乎不适用于复古传奇。
function* someGenerator() {
const state = yield select(); // execution freeze here when called from wrapper
const result = yield call(someEffect);
return result;
}
function wrapper() {
return co(someGenerator); // returns Promise
}这有可能吗?如果是的话,我做错了什么?
发布于 2017-07-10 14:58:59
Redux-saga是基于特殊原因的生成器函数--允许分离产生的部分并从位于内部saga进程管理器的一个端点管理它们。相反,在一般情况下,承诺是一种自我的东西,不能被部分地执行.换句话说,承诺管理它们所在的控制流,而生成器则由外部控制流管理。
当从包装器调用时,在这里生成select();//执行冻结
您的主要误解是假设select实际执行某些异步操作。不,它只是在这一点上暂停了函数somegenatator并将控制权转移到redux-saga引擎,后者知道这与返回值有关,并且可能在进程完成时状态异步进程(可能没有--没关系),saga引擎恢复生成器,并将返回值传递给它。
您可以在select (https://github.com/redux-saga/redux-saga/blob/master/src/internal/io.js#L139 )的源代码中轻松地看到它。它只是返回一个具有某种结构的对象,可以被saga引擎理解,然后引擎执行真正的操作,并以generatorName.next(resultValue)格式调用生成器。
UPD。纯理论上,你可以把它包装成可重新分配的承诺,但它是不可用的。
// Your library code
function deferredPromise() {
let resolver = null;
const promise = new Promise(resolve => (resolver = resolve));
return [
resolver,
promise
];
}
function generateSomeGenerator() {
let [ selectDoneResolve, selectDonePromise ] = deferredPromise();
const someGenetator = function* () {
const state = yield select(); // execution freeze here when called from wrapper
const [newSelectDoneResolve, newSelectDonePromise] = deferredPromise();
selectDoneResolve({
info: state, nextPromise: newSelectDonePromise
});
selectDoneResolve = newSelectDoneResolve;
selectDonePromise = newSelectDonePromise;
const result = yield call(someEffect);
return result;
}
return {
someGenetator,
selectDonePromise
};
}
const { someGenetator: someGenetatorImpl, selectDonePromise } = generateSomeGenerator();
export const someGenetator = someGenetatorImpl;
// Wrapper for interface
selectDonePromise.then(watchDone)
function watchDone({ info, nextPromise }) {
// Do something with your info
nextPromise.then(watchDone);
}https://stackoverflow.com/questions/44989971
复制相似问题