Ваш вопрос довольно сложный, и я могу ошибаться в некоторых аспектах.Но вот 3-4 идеи, которые могут помочь.
Идея 1
Из 'then' вы можете немедленно вызвать 'handler' с прокси, который запрещает в большинстве случаев каждыйоперация с ним.После того, как это сделано, вы просто наблюдаете за функцией, чтобы выйти или выдать ошибку.Таким образом, вы можете отслеживать, действительно ли возвращенное значение используется каким-либо образом.
Однако, если возвращенное значение не используется - вы его не увидите.Так что это позволяет использовать этот вид:
... some code ...
await myPromiser(); // << notice the return value is ignored
... some more code ...
Если это проблема для вас, то этот метод помогает только частично.Но если это проблема, то ваш последний вызов (пусть e = myPromiser (...)) также будет бесполезен, так как «е» можно игнорировать после.
Ниже, вконец этого ответа: JavaScript-код, который успешно различает ваши три случая
Идея 2
Вы можете использовать Babel для инструментов кода третьегоPartyCodeпрежде чем позвонить.Babel также может быть использован во время выполнения при необходимости.С его помощью вы можете: 2.1 Просто найти все способы использования myPromise и проверить, является ли он законным или нет.2.2 Добавляйте вызовы к некоторым функциям маркера после каждого ожидания или «.then» - таким образом вы сможете обнаружить все случаи с помощью Варианта 1.
Ответ 3
Если вы ищете способ узнать, является ли «Обещание» вашим или решенным - тогда ответ «нет такого пути».Proof (выполнить в 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
Это говорит нам о том, что код разрешения всегда выполняется вне текущего контекста вызова.Т.е. мы могли ожидать, что вызов функции 'resol' из Promise приведет к немедленному вызову всех подписанных функций, но это не так - 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);
})();