当前位置: 首页>前端>正文

JS消息队列左右无痕滚动 javascript消息队列

一、异步及术语

  • 并行: 指同一时刻内多任务同时进行;
  • 并发: 指在同一时间段内,多任务同时进行着,但是某一时刻,只有某一任务执行;
  • 堆: 内存中某一未被阻止的区域,通常存储对象(引用类型);
  • 栈: 后进先出的顺序存储数据结构,通常存储函数参数和基本类型值变量(按值访问);
  • 队列: 先进先出顺序存储数据结构。
  • 消息队列: 也叫任务队列,存储待处理消息及对应的回调函数或事件处理程序;
  • 执行栈: 也可以叫执行上下文栈,JavaScript执行栈,顾名思义,是由执行上下文组成,当函数调用时,创建并插入一个执行上下文,通常称为执行栈帧(frame),存储着函数参数和局部变量,当该函数执行结束时,弹出该执行栈帧;

PS:通常所说的并发连接数,是指浏览器向服务器发起请求,建立TCP连接,每秒钟服务器建立的总连接数,而假如,服务器处10ms能处理一个连接,那么其并发连接数就是100。

1.1 事件循环和Promise 和 setTimeout
  • 一个线程中,事件循环是唯一的,但是任务队列可以拥有多个。
  • 任务队列又分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为task与jobs。
  • macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
  • micro-task大概包括: process.nextTick, Promise, MutationObserver(html5新特性)
  1. 执行栈内执行上下文的同步任务按序执行,执行完即退栈,而当异步任务执行时,该异步任务进入等待状态(不入栈),同时通知线程:当触发该事件时(或该异步操作响应返回时),需向消息队列插入一个事件消息;
  2. 当事件触发或响应返回时,线程向消息队列插入该事件消息(包含事件及回调);
  3. 当栈内同步任务执行完毕后,线程从消息队列取出一个事件消息,其对应异步任务(函数)入栈,执行回调函数,如果未绑定回调,这个消息会被丢弃,执行完任务后退栈;
  4. 当线程空闲(即执行栈清空)时继续拉取消息队列下一轮消息,首先去拉取micro-task(微任务),直到所有执行完毕,然后循环再次从macro-task(宏任务)开始,这样一直循环下去。
  5. 主线程不断重复上面的第4步。
setTimeout(function() {
    console.log('timeout1');
    new Promise(function(resolve) {
        resolve();
    }).then(function() {
        console.log('timeout1_then')
    })
})
new Promise((a) => {
  a('ffff')
}).then(_ => {
  console.log("promise outer")
})
// 输出顺序
promise outer
timeout1
timeout1_then
2 toString()检测数据类型

通过call调用toString()方法,可以用来区分对象数组或其他数据类型。如果直接调用toString()数组会直接转化成字符串

console.log(toString.call([])) // [object Array]
    console.log(toString.call(undefined))  //[object Undefined]
    console.log(toString.call(null))  // [object Null]
    console.log(toString.call(this)) // [object Window]
    console.log(toString.call(function () {}))  // [object Function]
    console.log({a: 3}.toString())  // [object Object]
    console.log([1, 3].toString()) // 1,3
    console.log(function () {}.toString()) // function () {}
3. sort方法强化
// 数字字符等正确排序
    function s(a, b) {
      if (a > b) return 1
        return -1
    }
    // 分开浮点数和整数
    function m(a, b) {
      if (a > Math.floor(a)) return 1
      if (b > Math.floor(b)) return -1
    }
    let str = ['a', 'c', 'A', 'b', 'C', 'B', 1, 3, 2, 9, 4, 3, 5].sort(s). // [1, 2, 3, 3, 4, 5, 9, "A", "B", "C", "a", "b", "c"]
    let floor = [1, 4, 2, 4.22, 1.21, 2.44].sort(m).  //1, 4, 2, 4.22, 1.21, 2.44]
    console.log(str, floor)
3. this通过属性调用指向对象,函数调用指向window
var a = 2
    function method() {
      console.log(this.a)
    }
    var obj = {
      a: 3,
      d: method
    }
    var obj2 = {
      a: 4
    }
    obj.d() // 3
    // 作为对象属性调用时,this指向对象。
    obj2.me = obj.d //
    obj2.me()   // 4
    // 作为方法调用时this指向window,函数时引用类型,当执行赋值操作时,只是指针给到了fun变量,然后调用,通过变量直接调用,而不是通过对象的方法。
    var fun = obj.d  // 2
    fun()
4. reflow和repaint
  • repaint:重绘,在改变 DOM 元素的视觉效果时触发,即不涉及任何排版布局的问题时触发。
  • 回流,在某一个 DOM 元素的位置发生改变后触发,而且它会重新计算所有元素的位置和在页面中的占有的面积,所以reflow的影响比repaint更大,因为它将会影响它所有的children、ancestors及siblings。所以影响是针对整个页面的,整个页面都需要重新渲染。

优化:

  • 用display隐藏,然后进行相关操作,完成后展示。
  • 用class代替行内样式,将 reflow和repaint的次数缩减为一次。
5. 模块机制
var myModule = (function aa () {
      // 由于闭包的原因,不会被销毁,所以每个定义的心模块,都能添加到modules上。
      //
      var modules = {}
      function define (name, deps, impl) {
        //遍历执行各个依赖的相关函数。
        for (var i = 0; i < deps.length; i++) {
          deps[i] = modules[deps[i]]
        }
        // 将模块的api存储在一个根据名字来管理的模块列表
        //
        modules[name] = impl.apply(impl, deps)
      }
      function get (name) {
        return modules[name]
      }
      // 将方法暴露出去,供调用
      return {
        define: define,
        get: get
      }
    })()

    // 使用
    myModule.define('bar', [], function () {
      function hello(arg) {
        return 'hello ' + arg
      }
      return {
        hello: hello
      }
    })
    myModule.define('foo', ['bar'], function (bar) {
      var world = 'world'
      function dest() {
        console.log(bar.hello(world))
      }
      return {
        dest: dest
      }
    })
    //
    var bar = myModule.get('bar')
    var foo = myModule.get('foo')
    console.log(bar.hello('world'))
    foo.dest();
6. HTML DOM 的加载流程
  1. 解析HTML结构
  2. 加载外部脚本和样式表文件
  3. 解析并执行脚本
  4. 构造HTML DOM模型
  5. 加载图片等外部文件
  6. 页面加载完毕
7. toFixed()

toFixed() 保留几位小数,四舍五入。该方法是不准确的。所以在计算价格时,一定要小心。但是处理33.00这种价格显示时(确保后两位是0,也就是价格不会出现角,分),则ok。

1.35.toFixed(1)   // 1.4
1.335.toFixed(2)。// 1.33

解决方法:
function mineToFixed (num, s) {
    if (Number.isInteger(num)) {
        return num.toFixed(s)
    }
    var times = Math.pow(10, s);
    // parseInt 会舍掉小数位,所以0.4 + 0.5 会被舍掉,这样就模拟了四舍五入。
    var des = num * times + 0.5;
    des = parseInt(des, 10) / times;
    return des + ''
}
8. 整数判断方式
1、任何正整数都会被1整除,即余数是0。
function isInteger(obj) {
 return typeof obj === 'number' && obj%1 === 0
}
2、整数取整后还是等于自己
function isInteger(obj) {
 return Math.floor(obj) === obj
}
3、通过位运算判断
function isInteger(obj) {
 return (obj | 0) === obj
}
9. 判断字节数
function indentifyByte(str) {
      return str.charCodeAt(0).toString(16).length;
    }
    console.log(indentifyByte('?'))   // 4

function is32Bit(c) {
  return c.codePointAt(0) > 0xFFFF;
}
is32Bit("?") // true

问题:

1、 stringObject.charCodeAt(index) charCodeAt方法只能分别返回前两个字节和后两个字节的值。

var s = "?";
s.charCodeAt(0) // 55362
s.charCodeAt(1) // 57271

2、'?'.length // 2 使用length并不准确。

3、es6 codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。但是字符串包含二个字节和四个字节时。输入的索引并不能按照理想的方式处理。a通过索引2才能访问到。

let s = '?a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97

用ES6 的for of处理,
	let s = '?a';
    for (let ch of s) {
      console.log(ch.codePointAt(ch));
    }



https://www.xamrdz.com/web/2pq1928862.html

相关文章: