Как я могу получить возвращаемое значение из обратного вызова `setTimeout`?

рассмотрите этот код

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()?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
277
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Поскольку 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. Вы можете только транспилировать его (т.е. используя Babel).

yqlim 29.05.2019 03:51

Не могли бы вы использовать async/await, чтобы переписать этот пример??

Joji 31.05.2019 01:22
Ответ принят как подходящий

Просто измените эту строку в обертке:

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, чтобы переписать этот пример??

Joji 31.05.2019 01:22

Да, но чтобы использовать await вместо .then, вам нужно сначала обернуть этот код внутри функции, которая объявлена ​​как async. Обновлен пример кода выше.

chatnoir 31.05.2019 07:03

Другие вопросы по теме