• JavaScript 系列--JavaScript一些奇淫技巧的实现方法(一)简短的sleep函数,获取时间戳


    一、前言

    有些东西很好用,但是你未必知道;有些东西你可能用过,但是你未必知道原理。
    实现一个目的有多种途径,俗话说,条条大路通罗马。发散一下大家的思维以及拓展一下知识面。

    二、实现一个简短的sleep函数

    sleep函数主要用来做延迟执行的,很多编程语言都有sleep函数,但是javascript没有这个函数,我们实现一下:

    1、简单版本

    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);

    优点:简单粗暴,通俗易懂。

    缺点:确实sleep了,但是卡死了,cpu会飙升,精确度不准

    2、promise版本

    // 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,没有形成进程阻塞,不会造成性能和负载问题。

    缺点:虽然解决了回调函数的嵌套,但是还是不美观,而且异步不彻底,过程中停止执行。

    3、generator版本

    // 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 的逻辑来处理,不爽。

    co 之所以这么火并不是没有原因的,当然不是仅仅实现 sleep 这么无聊的事情,而是它活生生的借着generator/yield 实现了很类似 async/await 的效果!这一点真是让我三观尽毁刮目相看。

    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)
    })

    4、async/await版本

    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 更加语义,另外各个函数都是扁平的,不会产生多余的嵌套,代码更加清爽易读。

    缺点:ES7 语法存在兼容性问题,有 babel 一切兼容性都不是问题

    5、开源的版本

    在 javascript 优雅的写 sleep 等于如何优雅的不优雅,这里有 C++ 实现的模块:https://github.com/ErikDubbelboer/node-sleep

    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()的原理。

    1、普通版

    var timestamp=new Date().getTime()

    优点:具有普遍性,大家都用这个
    缺点:应该没有吧

    2、进阶版

    var timestamp = (new Date()).valueOf()

    valueOf 方法返回对象的原始值(Primitive,'Null','Undefined','String','Boolean','Number'五种基本数据类型之一),可能是字符串、数值或 bool 值等,看具体的对象。

    优点:说明开发者原始值有一个具体的认知,让人眼前一亮。
    缺点: 应该没有吧

    3、Date.now()方法

    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();
      };
    }

    4、终极版

    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 这个数字。

    前端知识点:隐式转换的妙用

     

  • 相关阅读:
    2019暑假集训 windy数
    2019暑假集训 数字游戏
    2019暑假集训 周年纪念晚会
    2019暑假集训 加分二叉树
    0013-求圆柱体体积
    0012-求滑动距离
    0011-绝对值函数
    0010-温度转换
    0009-乘法问题
    0008-三位数倒序问题
  • 原文地址:https://www.cnblogs.com/chengxs/p/10949075.html
Copyright © 2020-2023  润新知