有些东西很好用,可是你未必知道;有些东西你可能用过,可是你未必知道原理。 实现一个目的有多种途径,俗话说,条条大路通罗马。发散一下你们的思惟以及拓展一下知识面。javascript
sleep函数主要用来作延迟执行的,不少编程语言都有sleep函数,可是javascript没有这个函数,咱们实现一下:前端
function sleep(sleepTime){
for(var start = +new Date;+new Date - start<sleepTime;){}
}
var t1 = +new Date();
sleep(3000);
var t2 = +new Date();
console.log(t2-t1);
复制代码
优势:简单粗暴,通俗易懂。java
缺点:确实sleep了,可是卡死了,cpu会飙升,精确度不许node
// promise版本
function sleep(sleepTime){
return new Promise(resolve => setTimeout(resolve,sleepTime));
}
var t1 = +new Date();
sleep(3000).then(()=>{
var t2 = +new Date();
console.log(t2-t1);
})
复制代码
优势:实际上用了setTimeout,没有造成进程阻塞,不会形成性能和负载问题。git
缺点:虽然解决了回调函数的嵌套,可是仍是不美观,并且异步不完全,过程当中中止执行。github
// generotor版本
function sleep(sleepTime){
return function(cb){
setTimeout(cb.bind(this), sleepTime);
}
}
function* genSleep(){
var t1 = +new Date();
yield sleep(3000);
var t2 = +new Date();
console.log(t2-t1);
}
async(genSleep);
function async(gen){
const iter = gen();
function nextStep(it){
if(it.done) return ;
if (typeof it.value === "function") {
it.value(function(ret) {
nextStep(iter.next(ret))
})
} else {
nextStep(iter.next(it.value));
}
}
nextStep(iter.next());
}
复制代码
优势:跟promise同样优势,代码变得更简单干净。编程
缺点:就是每次都要执行 next() 显得很麻烦,虽然有 co(第三方包)能够解决,但就多包了一层,很差看,错误也必须按 co 的逻辑来处理,不爽。promise
co 之因此这么火并非没有缘由的,固然不是仅仅实现 sleep 这么无聊的事情,而是它活生生的借着generator/yield 实现了很相似 async/await 的效果!这一点真是让我三观尽毁另眼相看。bash
const co = require("co")
function sleep(sleepTime) {
return function(cb) {
setTimeout(cb.bind(this), sleepTime)
}
}
co(function*() {
const t1 = +new Date()
yield sleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
})
复制代码
function sleep(delay) {
return new Promise(reslove => {
setTimeout(reslove, delay)
})
}
!async function test() {
const t1 = +new Date()
await sleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
}()
复制代码
优势:同 Promise 和 Generator 优势。 Async/Await 能够看作是 Generator 的语法糖,Async 和 Await 相较于 * 和 yield 更加语义,另外各个函数都是扁平的,不会产生多余的嵌套,代码更加清爽易读。babel
缺点:ES7 语法存在兼容性问题,有 babel 一切兼容性都不是问题
在 javascript 优雅的写 sleep 等于如何优雅的不优雅,这里有 C++ 实现的模块:github.com/ErikDubbelb…
const sleep = require("sleep")
const t1 = +new Date()
sleep.msleep(3000)
const t2 = +new Date()
console.log(t2 - t1)
复制代码
优势:可以实现更加精细的时间精确度,并且看起来就是真的 sleep 函数,清晰直白。 缺点:缺点须要安装这个模块node-sleep。
前端知识点:Async/Await是目前前端异步书写最优雅的一种方式
上面实现 sleep 函数,咱们能够发现代码有 +new Date()获取时间戳的用法,这只是其中的一种,下面就说一下其余两种以及 +new Date()的原理。
var timestamp=new Date().getTime()
复制代码
优势:具备广泛性,你们都用这个 缺点:应该没有吧
var timestamp = (new Date()).valueOf()
复制代码
valueOf 方法返回对象的原始值(Primitive,'Null','Undefined','String','Boolean','Number'五种基本数据类型之一),多是字符串、数值或 bool 值等,看具体的对象。
优势:说明开发者原始值有一个具体的认知,让人眼前一亮。 缺点: 应该没有吧
Date.now()
复制代码
Date.now() 方法返回自1970年1月1日 00:00:00 UTC到当前时间的毫秒数。类型为Number。由于 now() 是Date的一个静态函数,因此必须以 Date.now() 的形式来使用。
优势:简单明了。
缺点:兼容性问题,ECMA-262 第五版中被标准化。
兼容性不支持时的兼容性代码:
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
复制代码
var timestamp = +new Date()
复制代码
优势:对 JavaScript 隐式转换掌握的比较牢固的一个表现 缺点:应该没有吧
咱们来分析一下,为何+new Date()拿到的时间戳?
那就是隐式转换,实质上仍是调用了valueOf()的方法。
注意:
(1)一元+ 运算符
一元 + 运算符将其操做数转换为 Number 类型并反转其正负。注意负的 +0 产生 -0,负的 -0 产生 +0。
+new Date() 至关于 ToNumber(new Date())
(2)toString 用来返回对象的字符串表示。
var obj = {};
console.log(obj.toString());//[object Object]
var arr = [];
console.log(arr.toString());//""空字符串
var date = new Date(); // Tue May 28 2019 22:05:58 GMT+0800 (中国标准时间)
console.log(date.toString());//"Tue May 28 2019 22:05:58 GMT+0800 (中国标准时间)"
复制代码
(3)valueOf()方法返回对象的原始值
valueOf()方法返回对象的原始值,多是字符串,述职或boolean值,看具体的对象。
var obj = {
name: "saucxs"
}
console.log(obj.valueOf()) //Object {name: "saucxs"}
var arr1 = [1,3]
console.log(arr1.valueOf()) //[1,3]
var date = new Date()
console.log(date.valueOf())//1456638436303
复制代码
// 如代码所示,三个不一样的对象实例调用valueOf返回不一样的数据 原始值指的是 'Null','Undefined','String','Boolean','Number','Symbol' 6种基本数据类型之一,上面已经提到过这个概念,这里再次申明一下。
最后分解一下其中的过程:+new Date():
(1)运算符 new 的优先级高于一元运算符 +,因此过程能够分解为:var time=new Date();+time
(2)根据上面提到的规则至关于:ToNumber(time)
(3)time 是个日期对象,根据 ToNumber 的转换规则,因此至关于:ToNumber(ToPrimitive(time))
(4)根据 ToPrimitive 的转换规则:ToNumber(time.valueOf()),time.valueOf() 就是 原始值 获得的是个时间戳,假设 time.valueOf()=1503479124652
(5)因此 ToNumber(1503479124652) 返回值是 1503479124652 这个数字。
前端知识点:隐式转换的妙用
【注:我是saucxs,也叫songEagle,松宝写代码,文章首发于sau交流学习社区(www.mwcxs.top),关注咱们天天阅读更多精彩内容】