Progressive Web App 开发指南

施工中

坑点

  1. Service Workers 目前还没有被授予访问 cookie 的能力,viahttps://github.com/WICG/cookie-store/issues/37https://github.com/w3c/ServiceWorker/issues/707https://github.com/w3c/ServiceWorker/issues/837。所以通过 session 鉴权的页面可能会出现异常。

前端基础拾遗之javascript篇

  1. 基本类型

  2. 继承实现

  3. macrotask 和 microtask
    事件循环每次只会入栈一个 macrotask ,主线程执行完该任务后又会先检查 microtasks 队列并完成里面的所有任务后再执行 macrotask。
    macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering
    microtasks: process.nextTick, Promises, Object.observe, MutationObserver
    https://juejin.im/entry/58d4df3b5c497d0057eb99ff
    https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context#

  4. Event Loop
    浏览器侧

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    requestAnimationFrame(() => {
    console.log(4);
    });
    new Promise((resolve, reject) => {
    console.log(1);
    resolve();
    })
    .then(() => {
    console.log(2);
    throw new Error("err");
    })
    .catch(() => {
    console.log(3);
    });
    setTimeout(() => {
    console.log(5);
    }, 0);
    requestIdleCallback(() => {
    console.log(6);
    });

    服务端侧,setImmediate 和 setTimeout 触发先后不固定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    new Promise((resolve, reject) => {
    console.log(1);
    resolve();
    })
    .then(() => {
    console.log(3);
    throw new Error("err");
    })
    .catch(() => {
    console.log(4);
    });
    setImmediate(() => {
    console.log(5);
    });
    setTimeout(() => {
    console.log(6);
    }, 0);
    process.nextTick(() => {
    console.log(2);
    });
  5. 原型
    Function.prototypeFunction.__proto__都指向Function.prototype,这就是鸡和蛋的问题怎么出现的。
    Object.prototype.__proto__ === null,说明原型链到Object.prototype终止。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function F() {}
    let f = new F();
    console.log(f.__proto__ === F.prototype);
    console.log(F.prototype.constructor === F);
    console.log(f.constructor === F);

    console.log(F.__proto__ === Function.prototype);
    console.log(Function.prototype.constructor === Function);
    console.log(F.constructor === Function);

    console.log(Function.__proto__ === Function.prototype);
    console.log(Function.prototype.constructor === Function);

    console.log(f.prototype === undefined);
    console.log(F.prototype.__proto__ === Object.prototype);
    console.log(Function.prototype.__proto__ === Object.prototype);
    console.log(Object.prototype.__proto__ === null);
  6. 依赖

  7. 数组的方法

    • slice
      slice() 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。且原始数组不会被修改。
    1
    2
    3
    4
    5
    6
    7
    8
    arr.slice();
    // [0, end]

    arr.slice(begin);
    // [begin, end]

    arr.slice(begin, end);
    // [begin, end)
    • shift
      shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
  8. 不同 TAB 页下通讯

    • BroadcastChannel,Chrome54、Firefox38 Support

      1
      2
      3
      4
      5
      6
      7
      8
      9
      // tab1
      const channel = new BroadcastChannel("channel-name");
      channel.onmessage = function(e) {
      console.log(e);
      };

      // tab2
      const channel = new BroadcastChannel("channel-name");
      channel.postMessage("some message");
    • Shared Workers,Chrome、Firefox29 Support

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      // work.js
      const connections = [];
      onconnect = function(e) {
      const port = e.ports[0];
      connections.push(port);
      port.onmessage = function(e) {
      connections.forEach(function(connection) {
      if (connection !== port) {
      connection.postMessage(e.data);
      }
      });
      };
      };

      // tab1
      const worker = new SharedWorker("worker.js");
      worker.port.onmessage = function(e) {
      console.log(e.data);
      };

      // tab2
      const worker = new SharedWorker("worker.js");
      worker.port.postMessage("hello tab1");
    • localStorage

      1
      2
      3
      4
      5
      6
      7
      // tab1
      window.onstorage = function(e) {
      console.log(e);
      };

      // tab2
      localStorage.setItem("key", "value");
    • window.opener

javascript audio 对象常用事件

最近在做一个媒体播放器,集成了图片+音频播放模式和视频播放模式,研究了下 js audio 对象的事件,整理了相关事件及触发顺序。

音频的初始加载事件顺序:依次触发 onloadstartonprogressonsuspend,然后 onprogressonsuspend 交替触发,直到触发 ondurationchangeonloadedmetadataonloadeddataoncanplayoncanplaythrough,加载完成。

点击播放后触发事件顺序:
onplayonplayingontimeupdate,播放控件开始缓冲部分音频文件onprogress,缓冲足够多的音频片段后触发onsuspend,当缓冲即将播放完后又触发onprogressonsuspend,依次循环直到音频全部缓冲完毕。

音频播放完毕后触发:
onpauseonended

暂停播放控件时触发:
onpause

从暂停恢复播放后触发:
onplayonplaying