编辑:我更新了这个问题,旧问题移动了here。
可以在此jsfiddle或下面的代码片段中找到POC
目标:
这里的目标是创建或者说模拟一个可以更新的promise,它的生命周期基本上可以重置。
可选地,我希望使用 inversion of control 对promise解析进行更多控制,如下所示:
const ex = {};
const prom = new Promise<T>((resolve, reject) => {
ex.resolve = resolve;
ex.reject = reject;
});
实现方式:
片段:
您可以键入新值,然后选择是拒绝还是解决promise。拒绝的值将突出显示。
默认情况下,promise被拒绝,值为default
。
编辑:默认附带.then()
回调(代码片段第85行)。因此,一旦你第一次解析或拒绝一个值,你会看到你的值被打印两次**,这是预期的行为。
class UpdatablePromise {
/**
* @param prom - the default promise object
* @param executor - optional ExternalExecutor argument to store executor internally.
* @returns UpdatablePromise
*/
constructor(prom, executor) {
this.value = undefined;
this.executors = [];
if (executor) this.executors.push(Object.assign({}, executor));
/**
* Call previous resolve/reject functions to fulfil previous promises, if any.
* helper function, just to reduce code duplication in `update` function.
*/
const prevResolvers = (type) => {
return (val) => {
const flag = type === "reject";
while (true) {
const executor = this.executors.shift();
if (executor) flag ? executor.reject(val) : executor.resolve(val);
else break;
}
return val;
};
};
const handler = {
get: (target, prop) => {
// console.log(prop);
if (prop === "update") {
// return a function which takes the new promise value and its executor as argument
return (v, executor) => {
// console.log('upd', v, this.value);
this.value = v;
if (executor) this.executors.push(executor);
// attach `then` function to the new promise, so that the old promises are fulfilled when the new one does
// this has no effect on already fulfilled promises.
v.then(
(val) => prevResolvers("resolve")(val),
(val) => prevResolvers("reject")(val)
);
};
} else if (typeof this.value === "undefined") {
// if value is undefined, i.e. promise was never updated, return default property values
return typeof target[prop] === "function" ?
target[prop].bind(target) :
target[prop];
}
// else, attach functions to new promise
else if (prop === "then") {
// console.log('then', this.value);
return (onfulfilled, onrejected) =>
this.value.then(onfulfilled, onrejected);
} else if (prop === "catch") {
return (onrejected) => this.value.catch(onrejected);
} else if (prop === "finally") {
return (onfinally) => this.value.finally(onfinally);
} else return target[prop];
},
};
return new Proxy(prom, handler);
}
}
const input = document.getElementById("input")
const output = document.getElementById("output")
const resBtn = document.getElementById("res")
const rejBtn = document.getElementById("rej")
const ex_1 = {
resolve: () => void 0,
reject: () => void 0,
};
const prom_1 = new Promise((resolve, reject) => {
ex_1.resolve = resolve;
ex_1.reject = reject;
});
const up = new UpdatablePromise(prom_1, ex_1)
// Await the promise
up.then(_ => print(_), _ => print(_))
// Print the value of promise, highlight if it is rejected
async function print() {
try {
const val = await up;
output.innerHTML += `
${val}`
} catch (e) {
output.innerHTML += `
<mark>${e}</mark>`
}
}
resBtn.addEventListener("click", () => {
up.update(Promise.resolve(input.value));
print();
})
rejBtn.addEventListener("click", () => {
up.update(Promise.reject(input.value));
print();
})
function consoleTest() {
const ex = {
resolve: () => void 0,
reject: () => void 0,
};
const prom = new Promise((resolve, reject) => {
ex.resolve = resolve;
ex.reject = reject;
});
const up = new UpdatablePromise(prom, ex);
setTimeout(() => ex.resolve("resolved"), 1000);
up.then(
(_) => console.log(_, "res"),
(_) => console.log(_, "rej")
);
setTimeout(async() => {
up.update(Promise.reject("reject"));
up.then(
(_) => console.log(_, "res"),
(_) => console.log(_, "rej")
);
}, 2000);
setTimeout(async() => {
up.update(Promise.resolve("res again"));
up.then(
(_) => console.log(_, "res"),
(_) => console.log(_, "rej")
);
}, 2500);
}
consoleTest();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<label for="input">Enter a value to update promise with:</label>
<input id="input" />
<div>
<button id="res">
resolve
</button>
<button id="rej">
reject
</button>
</div>
<pre id="output"></pre>
</body>
</html>
JS Fiddle
ts playground - ts版本(可能不会更新。更喜欢小提琴版本)
下面是打印promise值的部分:
// Print the value of promise, highlight if it is rejected
async function print() {
try {
const val = await up;
output.innerHTML += `
${val}`
} catch (e) {
output.innerHTML += `
<mark>${e}</mark>`
}
}
问题:
它 * 似乎 * 工作 * 有时 *,例如,在控制台或在小提琴。
但是当我在service worker中使用它时实际上不起作用,只返回promise的旧值。我用的是工作盒,如果有关系的话。
我还没找到问题所在下面是对我不起作用的实际工作框代码:
// If the refresh Token is resolved, the user is logged in, otherwise not.
class MyStrat extends Strategy {
async _handle() {
try {
await refreshToken;
return new Response(JSON.stringify({ is_logged_in: true }), {
status: 200,
headers: [[CONTENT_TYPE, APPLICATION_JSON]],
});
} catch (e) {
console.log('error', e);
return new Response(JSON.stringify({ is_logged_in: false }), {
status: 400,
headers: [[CONTENT_TYPE, APPLICATION_JSON]],
});
}
}
}
精确问题:
我想知道几件事
1.它真的像上面提到的那样有效吗?(即,它的工作方式与promise完全相同,除了它可以“重置”,并且一旦更新,所有挂起的await
s或附加的回调都会使用新的更新值来实现)
1.如果是,那么它在(工作盒的)service worker中不工作的原因是什么?
1.如果没有,那么实际上发生了什么?
1.如果它真的有效,那么是否可以添加一个state
成员变量来同步跟踪promise状态?(我试过一次,根本没用)
编辑二:
显然,这似乎也适用于服务工作者。由于其他一些函数,promise被重复更新为存储在数据库中的值。
不过,我还是想得到我其他问题的答案
1条答案
按热度按时间t9aqgxwy1#
它真的像我期望它在控制台或小提琴中工作一样工作吗?
只有你才能知道它是否符合你的预期。但是如果你说它可以工作,在控制台中,在小提琴中,(根据你的编辑)也在服务工人中,看起来它确实可以工作。
但是,这里没有充分的理由使用
Proxy
。如果你使用一个 Package 了promise的常规类示例,实现会变得更加清晰:是否可以添加一个
state
成员变量来同步跟踪promise状态?当然,只要加上
在每次将promise赋值给
this.value
之后(或者更好的是,将其放入helper方法中)。