How to get the return value of the setTimeout inner function in js All In One
How to get the return value of the setTimeout
inner function in js All In One
在 js 中如何获取
setTimeout
内部函数的返回值
✅ Promise wrap & Async / Await
js debounce
function debounce(func, delay) {
let id;
// ✅ ...rest 保证在不使用 arguments 的情况下,也可以传入不定数量的参数
return function (...args) {
console.log(`\nrest args =`, args);
console.log(`rest ...args =`, ...args);
console.log(`rest [...args] =`, [...args]);
let args1 = arguments;
let args2 = Array.prototype.slice.call(arguments, 0);
console.log(`args1 =`, args1);
console.log(`args2 =`, args2);
let context = this;
// let that = this;
clearTimeout(id);
id = setTimeout(() => {
// ✅ apply 接受参数数组 [arg1, arg2, ...]
func.apply(context, args);
// func.apply(context, [...args]);
// func.apply(context, ...args);
// Uncaught TypeError: CreateListFromArrayLike called on non-object
// ✅ call 接受参数列表 (arg1, arg2, ...)
func.call(context, ...args2);
}, delay);
};
};
raise a question
提出问题
如何获取 setTimeout 的返回值,以便可以自动化测试
,即可以使用测试用例
模版,跑通所有测试用例?
error
question analysis
问题分析
正常思路下,是不可能实现的,因为 setTimeout 是一个异步宏任务
不会阻塞 js 单线程
的执行,优先级最低,最后才会被执行;
故测试用例中执行读取结果的代码逻辑获取不到它的返回值,即测试代码逻辑已经执行了,结果还没返回;
那既然 setTimeout 是异步的,那就想办法阻塞它,让它的结果先返回,然后再执行读取结果的代码逻辑;
所以很容易想到使用 Promise
把 setTimeout 包装成一个微任务
,然后通过 Async/Await
来进行异步流程
的控制
Try it out
尝试验证
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2022-10-18
* @modified
*
* @description js debounce
* @description js debounce
* @difficulty Medium
* @time_complexity O(n)
* @space_complexity O(n)
* @augments
* @example
* @link https://www.cnblogs.com/xgqfrms/p/13849482.html
* @solutions
*
* @best_solutions
*
*/
const log = console.log;
// function debounce(func) {
// var id;
// return function (args) {
// console.log(`args 1 =`, args);
// var context = this;
// // var args = arguments;
// clearTimeout(id);
// id = setTimeout(() => {
// // func.apply(context, args);
// // func.apply(context, [...args]);
// func.apply(context, ...args);
// // Uncaught TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function
// });
// };
// };
// function debounce(func, delay) {
// let id;
// // ✅ ...rest 保证在不使用 arguments 的情况下,也可以传入不定数量的参数
// return function (...args) {
// console.log(`\nrest args =`, args);
// console.log(`rest ...args =`, ...args);
// console.log(`rest [...args] =`, [...args]);
// let args1 = arguments;
// let args2 = Array.prototype.slice.call(arguments, 0);
// console.log(`args1 =`, args1);
// console.log(`args2 =`, args2);
// let context = this;
// // let that = this;
// clearTimeout(id);
// id = setTimeout(() => {
// // ✅ apply 接受参数数组 [arg1, arg2, ...]
// func.apply(context, args);
// // func.apply(context, [...args]);
// // func.apply(context, ...args);
// // Uncaught TypeError: CreateListFromArrayLike called on non-object
// // ✅ call 接受参数列表 (arg1, arg2, ...)
// func.call(context, ...args2);
// }, delay);
// };
// };
const debounce = (func, delay) => {
let id;
// ✅ ...rest 保证在不使用 arguments 的情况下,也可以传入不定数量的参数
return async (...args) => {
console.log(`\nrest args =`, args);
console.log(`rest ...args =`, ...args);
console.log(`rest [...args] =`, [...args]);
let context = this;
// let that = this;
clearTimeout(id);
// id = setTimeout(() => {
// // ✅ apply 接受参数数组 [arg1, arg2, ...]
// func.apply(context, args);
// // func.apply(context, [...args]);
// // ✅ call 接受参数列表 (arg1, arg2, ...)
// // func.call(context, ...args);
// }, delay);
const promise = new Promise((resolve, reject) => {
id = setTimeout(() => {
resolve(func.apply(context, args));
}, delay);
});
// return promise;
const result = await(promise);
console.log(`result`, result);
return result;
// js how to get setTimeout inner function return value ✅ promise wrap & async / await
};
};
// function test (a, b, c, d) {
// const args = [...arguments];
// console.log(`test args =`, args);
// }
// const fn = debounce(test, 1000);
// fn(1,2,3);
// // fn(1,2,3,4);
// fn(1,2,3,4,5);
// 测试用例 test cases
const testCases = [
{
input: [1,2,3],
result: '1,2,3',
desc: 'value equal to "1,2,3"',
},
{
input: [1,2,3,4],
result: '1,2,3,4',
desc: 'value equal to "1,2,3,4"',
},
{
input: [1,2,3,4,5],
result: '1,2,3,4,5',
desc: 'value equal to "1,2,3,4,5"',
},
];
function test (a, b, c, d) {
const args = [...arguments];
console.log(`test args =`, args);
return args;
}
const func = debounce(test, 1000);
log(`func =`, func);
// func = [AsyncFunction (anonymous)]
// func = Promise { [Function (anonymous)] }
(async () => {
for (const [i, testCase] of testCases.entries()) {
async function testCaseAsyncFunc(i, testCase) {
const result = await func(...testCase.input);
log(`result =`, result);
// result = Promise { <pending> }
// TypeError: func is not a function
log(`test case ${i} result: `, result.join() === testCase.result ? `✅ passed` : `❌ failed`, result);
// log(`test case ${i} =`, testCase);
}
await testCaseAsyncFunc(i, testCase);
}
})();
apply
& call
& that
ES5 context vs ES6 scoped
// 2. setTimeout with return value
const debounce = (func, delay) => {
let id;
// ✅ ...rest 保证在不使用 arguments 的情况下,也可以传入不定数量的参数
return async (...args) => {
console.log(`\nrest args =`, args);
console.log(`rest ...args =`, ...args);
console.log(`rest [...args] =`, [...args]);
let that = this;
clearTimeout(id);
const result = await new Promise((resolve, reject) => {
id = setTimeout(() => {
// ✅ apply 接受参数数组 [arg1, arg2, ...]
// resolve(func.apply(that, args));
// test case 2 result: ✅ passed [ 1, 2, 3, 4, 5 ]
// resolve(func(args));
// test case 2 result: ✅ passed [ [ 1, 2, 3, 4, 5 ] ]
// 二维数组 潜在 bug ❌, 使用 call / apply 避免出现这种问题
resolve(func.apply(null, args));
// test case 2 result: ✅ passed [ 1, 2, 3, 4, 5 ]
}, delay);
});
return result;
// const promise = new Promise((resolve, reject) => {
// id = setTimeout(() => {
// // ✅ apply 接受参数数组 [arg1, arg2, ...]
// resolve(func.apply(that, args));
// }, delay);
// });
// const result = await(promise);
// console.log(`result =`, result);
// return result;
};
};
solutions
得出结论
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @created 2022-10-18
* @modified
*
* @description How to get the return value of the setTimeout inner function in js All In One
* @description 在 js 中如何获取 setTimeout 内部函数的返回值
* @difficulty Hard
* @time_complexity O(n)
* @space_complexity O(n)
* @augments
* @example
* @link https://www.cnblogs.com/xgqfrms/p/16806941.html
* @link https://www.cnblogs.com/xgqfrms/p/13849482.html
* @solutions
*
* @best_solutions
*
*/
const log = console.log;
// 1. no need return value
/*
function debounce(func, delay) {
let id;
// ✅ ...rest 保证在不使用 arguments 的情况下,也可以传入不定数量的参数
return function (...args) {
let that = this;
clearTimeout(id);
id = setTimeout(() => {
// ✅ apply 接受参数数组 [arg1, arg2, ...]
func.apply(that, args);
// func.apply(context, [...args]);
// ✅ call 接受参数列表 (arg1, arg2, ...)
// func.call(context, ...args2);
}, delay);
};
};
function test (a, b, c, d) {
const args = [...arguments];
console.log(`test args =`, args);
}
const fn = debounce(test, 1000);
fn(1,2,3);
fn(1,2,3,4);
fn(1,2,3,4,5);
*/
// 2. setTimeout with return value
const debounce = (func, delay) => {
let id;
// ✅ ...rest 保证在不使用 arguments 的情况下,也可以传入不定数量的参数
return async (...args) => {
console.log(`\nrest args =`, args);
console.log(`rest ...args =`, ...args);
console.log(`rest [...args] =`, [...args]);
let that = this;
clearTimeout(id);
const result = await new Promise((resolve, reject) => {
id = setTimeout(() => {
// ✅ apply 接受参数数组 [arg1, arg2, ...]
resolve(func.apply(that, args));
}, delay);
});
return result;
// const promise = new Promise((resolve, reject) => {
// id = setTimeout(() => {
// // ✅ apply 接受参数数组 [arg1, arg2, ...]
// resolve(func.apply(that, args));
// }, delay);
// });
// const result = await(promise);
// console.log(`result =`, result);
// return result;
};
};
// 测试用例 test cases
const testCases = [
{
input: [1,2,3],
result: '1,2,3',
desc: 'value equal to "1,2,3"',
},
{
input: [1,2,3,4],
result: '1,2,3,4',
desc: 'value equal to "1,2,3,4"',
},
{
input: [1,2,3,4,5],
result: '1,2,3,4,5',
desc: 'value equal to "1,2,3,4,5"',
},
];
function test (a, b, c, d) {
const args = [...arguments];
console.log(`test args =`, args);
return args;
}
const func = debounce(test, 1000);
log(`func =`, func);
// func = [AsyncFunction (anonymous)]
(async () => {
for (const [i, testCase] of testCases.entries()) {
async function testCaseAsyncFunc(i, testCase) {
const result = await func(...testCase.input);
log(`result =`, result);
log(`test case ${i} result: `, result.join() === testCase.result ? `✅ passed` : `❌ failed`, result);
// log(`test case ${i} =`, testCase);
}
await testCaseAsyncFunc(i, testCase);
}
})();
js debounce & js throttle
如何使用 js 实现一个 debounce 函数 All In One
https://www.cnblogs.com/xgqfrms/p/13849482.html
如何使用 js 实现一个 throttle 函数 All In One
https://www.cnblogs.com/xgqfrms/p/13849487.html
refs
https://gist.github.com/xgqfrms/497fb9278dce51275dde0a0635206886
https://splunktool.com/how-to-make-javascript-settimeout-returns-value-in-a-function
https://stackoverflow.com/questions/24928846/get-return-value-from-settimeout
Promise.resolve("foo")
// 1. Receive "foo", concatenate "bar" to it, and resolve that to the next then
.then((string) =>
new Promise((resolve, reject) => {
setTimeout(() => {
string += "bar";
resolve(string);
}, 1);
})
)
//...
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#链式调用
©xgqfrms 2012-2020
www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!
原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/16806941.html
未经授权禁止转载,违者必究!