рассмотрите этот код
const obj = {
generate(num) {
return Math.random()*num;
},
add(a,b) {
return this.generate(a) + this.generate(b)
}
};
function delay(func, ms) {
function wrapper() {
setTimeout(() => func.apply(this, arguments), ms) // How can I get the return value from the original function?
}
return wrapper;
}
// create wrappers
obj.f1000 = delay(obj.add, 1000);
obj.f1500 = delay(obj.add, 1500);
obj.f1000(1,3);
obj.f1500(2,5);
Я сделал обертку, чтобы отложить вызов метода для add()
Есть ли способ получить значение из обратного вызова внутри setTimeout, то есть this.generate(a) + this.generate(b)
из add()
?
Поскольку setTimeout будет выполнять обратный вызов асинхронно, вам нужно будет работать с Promises (ES6) или async/await (ES7).
Вы можете полифилл для ES5.
const obj = {
generate(num) {
return Math.random() * num;
},
add(a, b) {
return this.generate(a) + this.generate(b);
}
};
// create promise
function timedPromise(func, args, ms) {
return new Promise(resolve => {
setTimeout(() => {
// spread operator
resolve(func.apply(null, args));
}, ms);
});
}
// create a function that creates a promise
function delay(func, ms) {
function wrapper() {
return timedPromise(func, arguments, ms);
}
return wrapper;
}
// obj.add uses this.generate, but 'this' was not bound to obj
obj.f1000 = delay(obj.add.bind(obj), 1000);
obj.f1500 = delay(obj.add.bind(obj), 1500);
console.info('calculating...')
const result1 = obj.f1000(1, 3);
const result2 = obj.f1500(2, 5);
result1.then(result => {
console.info('f1000', result);
})
result2.then(result => {
console.info('f1500', result);
})
В вашей функции-оболочке вы привязали this
к вызываемой функции. Но так как this
не был определен в этой конкретной области, у вас возникли бы некоторые проблемы. Я связал obj
с функцией add
, передав ее delay()
.
Не могли бы вы использовать async/await
, чтобы переписать этот пример??
Просто измените эту строку в обертке:
setTimeout(() => func.apply(this, arguments), ms)
вернуть Обещать (ES6)
return new Promise(resolve => setTimeout(() => resolve(func.apply(this, arguments)), ms));
Вы можете получить доступ к отложенному результату через .then
.
Обновлять По запросу OP ответ отредактирован, чтобы использовать async/await
вместо then
. Поскольку await
нужно вызывать внутри функции, объявленной как async
, нам нужно обернуть наш js-код внутри новой функции (main()
ниже):
const obj = {
generate(num) {
return Math.random() * num;
},
add(a, b) {
return this.generate(a) + this.generate(b)
},
};
function delay(func, ms) {
function wrapper() {
// CHANGE THIS LINE
return new Promise(resolve => setTimeout(() => resolve(func.apply(this, arguments)), ms)); // How can I get the return value from the original function?
}
return wrapper;
}
//await can only work in an 'async' function
async function main() {
obj.f1000 = delay(obj.add, 1000);
console.time('completed');
// add await here
let x = await obj.f1000(1, 3);
console.info(x);
console.timeEnd('completed');
}
main();
Не могли бы вы использовать async/await, чтобы переписать этот пример??
Да, но чтобы использовать await
вместо .then
, вам нужно сначала обернуть этот код внутри функции, которая объявлена как async
. Обновлен пример кода выше.
Примечание. Вы не можете полифилить синтаксис async/await. Вы можете только транспилировать его (т.е. используя Babel).