Js再起之遗漏的睡眠之异步回调
疑问: js有sleep()吗?
settimeout
- settimeout添加的事件, 会在下一次event loop执行, 问题出现了,
- 我的代码里面5000*5000的循环, 然后如果循环内部的settimeout, 也就是要在5000X5000之后执行, 问题严重了. 这个一定是有问题的.
- 因此, settimeout对我的这个场景无用.
settimeout小技巧: 传递参数
settimeout的第一个参数是一个function, js的规则function作为指针传递的时候, 都是不能指定参数的, 参数是由外部调用指定的, 在这个例子中, 如果这个function有参数, 也是settimeout自动指定的. 因此, 要传递参数, 需要一点小技巧, 两个写法都可以.
//包在外边
setTimeout(
function(){
httppre(json[i].stationName, json[j].stationName, '2017-12-16')//这里写多少的参数都可以.
}, 1000
)
//包在里面
function fun2(objectP){
return function(){
// 这里开始干正事, 那个参数ObjectP都可以用了.
}
}
setTimeout(fun2(p), 100);
//如果是字符串作为参数, 可以不那么麻烦, 问题来了, 多个参数咋办?
setTimeout("fun1('" + paramenter + "')", 100);
//这种形式不是太好, 因为其实是一个eval
//更完美的解决方案: Function.prototype.bind()
setTimeout(函数名.bind(null, topicId), 4000);
第一个参数, 可以传递一个函数指针(比如this)进去, 他指明了this的指向.
//第三个参数可以作为第一个参数(函数)的参数
setTimeout(alert, 1000, hello);
setTimeout(yourFunctionReference, 4000, param1, param2, paramN);
//匿名函数也可以直接带参数, 但是这种写法会导致括号套括号, 这个写法和前面的[第三个参数]其实是一样的.
setTimeout(function(参数) { //做点啥
}, i++ * 1000, 参数);
setTimeout(() => console.log(testObject[propertyName]), i++ * 1000);
//还可以用apply解决, 有兴趣的可以去研究下.
比如定时保存, 不论是ajax还是file本地保存
我们的策略都是一段时间没有保存, 才保存他, 而不是过于频繁的保存.
因此, 当用户敲击键盘我们就设置一个timeout保存, 然后, 用户再次敲击, 我们发现间隔很短, 就把之前的保存取消掉. 比如4s钟之内的.
function debounce(fn, delay){
var timer = null; // 声明计时器
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
//由于timer声明在外边, 因此对于匿名函数而言, timer一直记录了之前的一个, 所以, 每次只要简单的取消前面一个timer就好了, 完全不必写任何的判断.
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
};
}
// 用法示例
var todoChanges = debounce(batchLog, 1000);
Object.observe(models.todo, todoChanges);
没事就用settimeout是不合理的, 因为他有附加的cpu开销. js其实是单进程轮询机制, 轮询的内容越多, 轮询的效率必然越差.
这个blog写的比我的好, 本文大量参考/引用: https://jeffjade.com/2016/01/10/2016-01-10-javacript-setTimeout/
sleep的几种写法
//promise写法
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
console.log('Taking a break...');
await sleep(2000);
console.log('Two second later');
}
demo();
// sleep time expects milliseconds
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
// Usage!
sleep(500).then(() => {
// Do something after the sleep!
});
//玩命死循环判断时间的sleep是搞笑呢, 他完全堵塞了进程. 甚至于假死了整个computer.
//所以可以转变思路, 在需要timeout的地方, 控制timeout的间隔, 达到sleep的效果.
关于pormise的解释
//很不爽, 要用promise, 需要先创建Pormise对象, 如果这个对象是返回值. 那么那他就可以链式了.
new Promise( function(resolve, reject) {...} /* executor */ );
resolve和reject分别是两个函数. 对应于匿名函数执行状态(成功/失败).
//他替代了这种写法:
function successCallback(result) {
console.log("It succeeded with " + result);
}
function failureCallback(error) {
console.log("It failed with " + error);
}
doSomething(successCallback, failureCallback);
//这么写了:
let promise = doSomething();
promise.then(successCallback, failureCallback);
//更简洁的:
doSomething().then(successCallback, failureCallback);
//这种写法的要点: dosomething不需要后面的参数, then才需要.
//dosomething返回的函数是一个也已用then处理successCallback, failureCallback的函数.
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
//更简单写法:
let promise2 = doSomething().then(successCallback, failureCallback);
//多重回调, 会导致括号套括号.
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
//基于promise的链式写法
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
//then里的参数是可选的,catch(failureCallback) 是 then(null, failureCallback) 的缩略形式。也可以用 arrow functions(箭头函数)来表示:
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
//举例
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
//由于“Something failed”错误导致了拒绝操作,所以“Do this”文本没有被输出
console.log('Do this');
})
.catch(() => {
console.log('Do that');
})
.then(() => {
console.log('Do this whatever happened before');
});
参考: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
promise和错误传递
doSomething()
.then(result => doSomethingElse(value))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
//语法糖形式:
async function foo() {
try {
let result = await doSomething();
let newResult = await doSomethingElse(result);
let finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch(error) {
failureCallback(error);
}
}
promise 和settimeout
//理想状态下,所有的异步函数都已经返回promise了。但有一些API仍然使用旧式的被传入的成功或者失败的回调。典型的例子就是setTimeout()函数, 所以要用promise包裹.
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);
//通常,promise的构造器会有一个可以让我们手动操作resolve和reject的执行函数。既然 setTimeout 没有真的执行失败,那么我们可以在这种情况下忽略reject。
new async/await/Promise 这三个是一套.
我理解的promise
xxx().then(成功函数, 失败函数).then(成功函数, 失败函数).then(成功函数, 失败函数)
要想形成链式, 成功函数和失败函数的返回值也要是函数.
doSomething()
.then(result => doSomethingElse(result)) //当省略{}时,箭头函数将隐式返回
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(() => { console.log('Do that');});
//catch(failureCallback) 是 then(null, failureCallback) 的缩略形式。
promise的变形: async/await语法糖
async function foo() {
try {
let result = await doSomething();
let newResult = await doSomethingElse(result);
let finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch(error) {
failureCallback(error);
}
}
promise对timeout的处理
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);