gpt4 book ai didi

javascript - 检测异步函数的 "returned promise only"状态

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:08:38 25 4
gpt4 key购买 nike

我有这样的情况:

async function thirdPartyCode(a) {
if (a == ...) {
return myPromiser(...) // can allow and act on this
}
let b = await someoneElsesPromiserB(...)
if (b == ...) {
let c = await myPromiser(...) // must error on this
...
}
let d = await someoneElsesPromiserD(...)
let e = myPromiser(...) // note no await
return e // can allow and act on this
}

作为 myPromiser() 的作者和此 thirdPartyCode() 的调用者,我想检测 myPromiser() 的 promise 是否用作异步函数的返回 promise 。这是在这种特殊类型的异步函数的调用上下文中使用它的唯一合法方式。当它在此函数内时,不能等待它,也不能附加 .then() 子句。

如果有办法知道“异步函数的主体何时实际上完成”,那将是解决它的一个楔子。

(注意:这个问题中的奇怪限制是使用 Emscripten Emterpreter 的副产品。当 simulated pthreads 可通过 WebAssembly worker/SharedArrayBuffer 等获得时,这些限制可能(?)不需要适用。但在撰写本文时,这些前沿浏览器功能并未默认启用……因此,这种不寻常的愿望来自于希望兼容的代码子集是合法的。)

最佳答案

你的问题很复杂,我可能在某些方面理解错了。但这里有 3-4 个想法可能会有所帮助。

想法一

从“then”开始,您可以使用 Proxy 立即调用“handler”,这几乎禁止对其进行的所有操作。完成此操作后,您只需观察函数退出或抛出错误即可。通过这种方式,您可以跟踪返回值是否以任何方式实际使用。

但是,如果未使用返回值 - 您将看不到它。所以这允许这种用途:

    ... some code ...
await myPromiser(); // << notice the return value is ignored
... some more code ...

如果这对您来说是个问题,那么此方法只能起到部分帮助。但如果这是一个问题,那么你最后一次调用 (let e = myPromiser(...)) 也将毫无用处,因为之后可以忽略“e”。

下面,在这个答案的末尾成功区分三种情况的 javascript 代码

想法 2

您可以在调用“thirdPartyCode”代码之前使用 Babel 检测它。如果需要,Babel 也可以在运行时使用。有了它,您可以:2.1 找出myPromise的所有用法并检查其是否合法。2.2 在每个 await 或 '.then' 之后添加对一些标记函数的调用 - 这样您就可以使用选项 1 检测所有情况。

答案 3

如果您正在寻找一种方法来了解 Promise 是您的还是已解决 - 那么答案是“没有这种方法”。证明(以Chrome运行为例):

    let p = new Promise((resolve, reject)=>{
console.log('Code inside promise');
resolve(5);
});
p.then(()=>{
console.log('Code of then')
})
console.log('Code tail');

// Executed in Chrome:
// Code inside promise
// Code tail
// Code of then

这告诉我们 resolve 的代码总是在当前调用上下文之外执行。IE。我们可能一直期望从 Promise 内部调用“resolve”会导致立即调用所有订阅的函数,但事实并非如此——v8 将等到当前函数执行结束,然后才执行处理程序。

想法4(部分)

如果你想拦截对 SystemPromise.then 的所有调用并决定你的 Promiser 是否被调用 - 有一种方法:你可以用你的实现覆盖 Promise.then。

不幸的是,这不会告诉您异步功能是否结束。我已尝试对其进行试验 - 请参阅下面我的代码中的注释。


答案1的代码:

    let mySymbol = Symbol();
let myPromiserRef = undefined;

const errorMsg = 'ANY CUSTOM MESSAGE HERE';
const allForbiddingHandler = {
getPrototypeOf: target => { throw new Error(errorMsg); },
setPrototypeOf: target => { throw new Error(errorMsg); },
isExtensible: target => { throw new Error(errorMsg); },
preventExtensions: target => { throw new Error(errorMsg); },
getOwnPropertyDescriptor: target => { throw new Error(errorMsg); },
defineProperty: target => { throw new Error(errorMsg); },
has: target => { throw new Error(errorMsg); },
get: target => { throw new Error(errorMsg); },
set: target => { throw new Error(errorMsg); },
deleteProperty: target => { throw new Error(errorMsg); },
ownKeys: target => { throw new Error(errorMsg); },
apply: target => { throw new Error(errorMsg); },
construct: target => { throw new Error(errorMsg); },
};


// We need to permit some get operations because V8 calls it for some props to know if the value is a Promise.
// We tell it's not to stop Promise resolution sequence.
// We also allow access to our Symbol prop to be able to read args data
const guardedHandler = Object.assign({}, allForbiddingHandler, {
get: (target, prop, receiver) => {
if(prop === mySymbol)
return target[prop];

if(prop === 'then' || typeof prop === 'symbol')
return undefined;

throw new Error(errorMsg);
},
})

let myPromiser = (...args)=> {
let vMyPromiser = {[mySymbol]:[...args] };
return new Proxy(vMyPromiser,guardedHandler);
// vMyPromiser.proxy = new Proxy(vMyPromiser,guardedHandler);
// vMyPromiser.then = ()=> {
// myPromiserRef = vMyPromiser;
// console.log('myPromiserThen - called!');
// return vMyPromiser.proxy;
// }
// return vMyPromiser;
};

let someArg = ['someArgs1', 'someArgs2'];

const someoneElsesPromiserB = async(a)=>{
return a;
}

const someoneElsesPromiserD = async(a)=>{
return a;
}

async function thirdPartyCode(a) {
console.log('CODE0001')
if (a == 1) {
console.log('CODE0002')
return myPromiser(a, someArg) // can allow and act on this
}

console.log('CODE0003')
let b = await someoneElsesPromiserB(a)
console.log('CODE0004')
if (b == 2) {
console.log('CODE0005')
let c = await myPromiser(a, someArg) // must error on this
console.log('CODE0006')
let x = c+5; // <= the value should be used in any way. If it's not - no matter if we did awaited it or not.
console.log('CODE0007')
}
console.log('CODE0008')
let d = await someoneElsesPromiserD(a);
console.log('CODE0009')
let e = myPromiser(a, someArg) // note no await
console.log('CODE0010')
return e // can allow and act on this
};


// let originalThen = Promise.prototype.then;
// class ReplacementForPromiseThen {
// then(resolve, reject) {
// // this[mySymbol]
// if(myPromiserRef) {
// console.log('Trapped then myPromiser - resolve immediately');
// resolve(myPromiserRef.proxy);
// myPromiserRef = undefined;
// } else {
// console.log('Trapped then other - use System Promise');
// originalThen.call(this, resolve, reject);
// }
// }
// }
//
// Promise.prototype.then = ReplacementForPromiseThen.prototype.then;

(async()=>{
let r;
console.log('Starting test 1');
r = await thirdPartyCode(1);
console.log('Test 1 finished - no error, args used in myPromiser = ', r[mySymbol]);
console.log("\n\n\n");

console.log('Starting test 3');
r = await thirdPartyCode(3);
console.log('Test 3 finished - no error, args used in myPromiser = ', r[mySymbol]);
console.log("\n\n\n");

console.log('Starting test 2 - should see an error below');
r = await thirdPartyCode(2);
})();

关于javascript - 检测异步函数的 "returned promise only"状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55186667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com