1

だから私は<img>自分のページにタグを持っています。

<img id="the_image" src="/imageServlet">

/imageServlet が、ブラウザーがこの画像をキャッシュしてはならないことを示すいくつかの HTTP 応答ヘッダーで応答していると仮定しましょう。この場合の理由は、画像に従業員の機密情報が含まれている可能性があり、特定の国では、マシンが盗まれた場合にブラウザーが (ユーザーの同意なしに) クライアントのハード ドライブに画像を保存してはならないという法律があるためです。応答ヘッダーはCache-Control: no-cache

私が本当にやりたいことは、この画像タグを複製することだけですが、この画像に対して別の HTTP 要求が行われることは望ましくありません。

私のアプリケーションは単一のページで、javascript を使用してこれらの画像タグを動的に使用していますが、この同じ画像を複数の場所に表示したいと考えています。たとえば、画像はユーザーのプロフィール写真のサムネイル バージョンである可能性があります。ある場所ではサムネイルを小さなリストとして表示し、そのユーザーをクリックすると同じ画像をポップアップで表示します。

この src で新しいタグを作成するたび<img>に、ブラウザはサーバーに新しい呼び出しを行って画像を取得しています。ユーザーがブラウザーで「更新」を押して、その画像の新しい HTTP 要求が読み込まれるかどうかは気にしませんが、1 つのページの読み込み内で、画像データがメモリ内で利用可能であってはならないので、再利用できませんでしたこれ?

どうすればこれを回避できますか? これは、画像が再利用されて複数の場所に表示されるページのパフォーマンスに大きな影響を与え、(ユーザーが他のページに移動したりブラウザーを更新したりしていなくても) 毎回再読み込みする必要があります。

これは、アプリケーションが画像をロードしたいときはいつでも「loadImage」を呼び出し、最終的に自由に使用できる HTML 要素でコールバックを呼び出すという考えで、今書いたコードです。アイデアは、この中央関数がイメージを作成することですがsrc、HTTP 応答ヘッダーに含まれているかどうかに関係なく、一意の HTTP 要求が 1 つだけ作成されるようにしますCache-Control: no-cache

(function(){
  var HANDLERS = {};

  /**
   * I want to keep around a cached "Image" then the "callback" will be called with a
   * duplicate somehow - whatever comes back from here can be inserted somewhere, but
   * hopefully no additional HTTP requests needs to be made!!
   * @param {Image} img
   * @return {Image} A copy of the incoming img
   */
  function duplicateImage(img) {
    // Does not work!! D'oh, is this even possible to achieve??
    return img.cloneNode(true);
  }

  /**
   * Users can call this to load the image. The callback is called when the image is ready.
   * In case the image fails the callback will be given an object that contains a success flag.
   * 
   * Example:
   * loadImage('/imageServlet?xxxx', function(result) {
   *   if (result.success) { $(body).append(result.image); }
   *   else { console.log("The image failed to load!") }
   * });
   * 
   * @param {string} src The src for the image
   * @param {function({success:boolean, image:Image})} callback Give a callback to be called when ready
   */
  window.loadImage = function(src, callback) {
    if (!HANDLERS[src]) {
      var queue = [];

      // This loadImage can be called more than once with the same src
      // before the image has successfully loaded. We will queue up any
      // callbacks and call them later, then replace this with function
      // that will directly invoke the callback later.
      HANDLERS[src] = function(callback) {
        queue.push(callback);
      }

      // Create the image here, but do it only once!!
      var el = new Image();

      // When the image loads, we will keep it around in the el
      // variable, but the callback will be called with a copy
      el.onload = function() {
        el.onload = el.onerror = null;
        var call = HANDLERS[src] = function(callback) {
          callback({
            success: true,
            image: duplicateImage(el) // This is where the image is duplicated!
          });
        }
        for (var i=0; i<queue.length; i++) {
          call(queue[i]);
        }
      }

      // This is just in case the image fails to load. Call any
      // queued callbacks with the success false.
      el.onerror = function() {
        el.onload = el.onerror = null;
        var call = HANDLERS[src] = function(callback) {
          callback({success: false});
        }
        for (var i=0; i<queue.length; i++) {
          call(queue[i]);
        }
      }
      el.src = src;
    }
    HANDLERS[src](callback);
  }
})();
4

2 に答える 2

3

ページが画像データの取得を開始したときに ajax 呼び出しを試行し、そのデータを「コピー」する画像の「​​src」に割り当てます。

$.ajax({
    type: "GET",
    url: 'some url',
    datatype:"image/jpg",
        success: function (data) {
            $('#img1').attr('src', url.createObjectURL(data));
            $('#img2').attr('src', url.createObjectURL(data));
        }
});

これにより実際のイメージがリンクではなく「src」フィールドに書き込まれるため、後でこのイメージを 1 つのコントロールから別のコントロールにコピーすることができます。これ以上サーバーに要求する必要はありません。

$('#img3').attr('src', $('#img2').attr('src'));

jQuery 以外のバージョン

function myAjax() {
    var xmlHttp = new XMLHttpRequest();
    var url="some url";
    xmlHttp.open("GET", url, true);
    xmlHttp.setRequestHeader("Content-type", "image/jpg");
    xmlHttp.setRequestHeader("Connection", "close");
    xmlHttp.onreadystatechange = function() {
        if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
            document.getElementById('img1').setAttribute('src', xmlHttp.responseBinary);
        }
    }
    xmlHttp.send();
}
于 2013-10-22T03:53:53.027 に答える
0

画像が読み込まれたかどうかを JavaScript が判断できるように、ファイル名 ("src") を配列に格納することができます。キャンバスを使用して画像をレンダリングできます...画像がキャンバスに読み込まれたら、toDataURL() を使用してこの画像を複製できます...サーバーからフェッチする必要はありません。

于 2013-10-22T05:16:31.820 に答える