共享Ajax请求的不同方式的优势

问题描述 投票:0回答:1

我有一个显示实时信息的Intranet Web系统。有服务器端进程将各种更新记录到数据库中。然后,各种网页都使用Ajax每隔几秒钟询问新内容。这都是标准的东西(想想RSS ...),到目前为止还可以。

但是...如果用户显示多个页面,这将导致多个Ajax请求-每个请求实际上都要求相同的数据。这对一些用户没有害处,但扩展性不好。因此,我希望每个用户有一个请求。有很多选项:

  1. 每页使用Ajax进程并接受重复项
  2. 在每个页面中使用服务器发送的事件(即让浏览器进行处理)
  3. 具有第一页将更新馈入本地存储,而其他页面捕获“存储”事件
  4. 将Ajax移至将消息发布到页面的网络工作者中
  5. 我错过了选项吗?

关于不同选择的相对收益/痛苦,您有什么想法吗?

ajax local-storage web-worker server-sent-events
1个回答
0
投票

这听起来像SharedWorker的工作。

您所有的页面都将订阅它,并等待它传输资源:

下面是live fiddle演示中的代码(不允许从StackSnippet生成null的帧来运行SharedWorkers。

const script_content = document.getElementById('worker-script').textContent;
const script_url = URL.createObjectURL( new Blob( [ script_content ] ) );

// This should be the only one per page
const worker1 = new SharedWorker( script_url );
worker1.port.onmessage = (e) => console.log('worker1 received data', e.data);
// This would be an other page
const worker2 = new SharedWorker( script_url );
worker2.port.onmessage = (e) => console.log('worker2 received data', e.data);
<script id="worker-script" >
    const ports = []; // we'll store all the connected ports here
    onconnect = e => { / everytime a process connects
      ports.push( e.ports[ 0 ] );
    };
    setInterval( () => {
        const rand = Math.random(); // fetched data
        // transmit it to all connected processes
        ports.forEach( port => port.postMessage( rand ) );  
      }, 1000
    );
</script>


SharedWorker的最大问题是浏览器支持。您将无法在Safari上使用它。

但是我们现在有了the BroadcastChannel API,它允许在同一域上的不同进程之间进行通信,并且由于存储事件而可以很容易地进行多文件归档。

因此,您可以尝试建立一个与SharedWorker相同的系统,但是要稍微复杂一些。

当浏览器连接到您的页面之一时,它将尝试加入BroadcastChannel或创建它。

它首先通过BroadcastChannel发送一条消息,询问是否有人连接。

  • 如果没有人连接,则此过程将负责获取。

    • 每当它从服务器获得响应时,它将通过BroadcastChannel将其分派给所有其他进程。
    • [当进程即将被杀死时(例如,在BroadcastChannel中,它告诉连接的进程选择一个作为新的访存程序。
  • 否则

    • [[可选]它将自己置于继承人列表中
    • 它等待提取程序通过BroadcastChannel提供数据。

[onbeforeunload,因为虽然允许StackSnippet奇怪地运行BroadcastChannel,但它们的null起源将使它们无法与任何实例共享...在几个选项卡中打开此链接,并查看他们如何相互交谈。

这里仍然是小提琴的代码:

Here is a jsfiddle proof of concept
const my_id = Math.random();
let I_am_the_master = false;
let connections = ["me"];
const master_timeout = ImDaMasta();

const channel = new BroadcastChannel('demo');

channel.onmessage = e => {
  console.log(e.data);
  switch (e.data.type) {
    case "newData":
      onnewdatareceived(e.data.data);
      break;
    case "disconnect":
      ondisconnect(e);
      break;
    case "connect":
      onconnect(e);
      break;
    case my_id:
      oninitresponse(e);
  }
};

channel.postMessage({
  type: 'connect',
  _id: my_id
});


onbeforeunload = e => {
  channel.postMessage({
    type: 'disconnect',
    index: connections.indexOf('me')
  });
}

// set ourselves as the master process
function ImDaMasta() {
  I_am_the_master = true;
  return setInterval(() => {
    const rand = Math.random();
    channel.postMessage({
      type: "newData",
      data: rand
    });
    log("I'm the master and did post", rand);
  }, 1000);
}
// when we receive new data from the master
function onnewdatareceived(data) {
  log("I'm a slave and received", data);
}
// when an other process disconnected
function ondisconnect(e) {
  connections.slice(e.data.index, 1);
  if (connections[0] === "me") {
    ImDaMasta();
  }
}
// when an other process connects
function onconnect(e) {
  connections.push('other');
  if (I_am_the_master) {
    channel.postMessage({
      type: e.data._id,
      connections
    });
  }
}
// when the master process handled our connection
function oninitresponse(e) {
  I_am_the_master = false;
  clearTimeout(master_timeout);
  connections = e.data.connections;
  connections[connections.length - 1] = "me";
}


// helper
function log(...args) {
  _log.textContent = args.map(o => JSON.stringify(o)).join(' - ');
}
© www.soinside.com 2019 - 2024. All rights reserved.