成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

jasmine-ajax源碼解析

劉明 / 2543人閱讀

摘要:總體概述主要五個對象組成請求偽造對象請求跟蹤對象請求攔截對象用作對偽造的請求做出響應(yīng)。請求攔截跟蹤對象參數(shù)解析輔助函數(shù)函數(shù)結(jié)構(gòu)很明顯,判定一個數(shù)組是否包含某一個值。主要負(fù)責(zé)值的解析。若決定調(diào)用,則遍歷結(jié)束,返回該對象。

總體概述

jasmine-ajax主要五個對象組成:

請求偽造對象(FackXMLHttpRequest):

function FakeXMLHttpRequest() {}

請求跟蹤對象(RequestTracker):

function RequestTracker() {}

請求攔截對象(RequestStub):用作對偽造的AJAX請求做出響應(yīng)。

function RequestStub(url, stubData, method) {}

請求攔截跟蹤對象(StubTracker):

function StubTracker() {}

參數(shù)解析(ParamParser):

function ParamParser() {}
輔助函數(shù) arrayContains
function arrayContains(arr, item) {
for (var i = 0; i < arr.length; i++) {
  if (arr[i] === item) {
    return true;
  }
}
return false;
}

函數(shù)結(jié)構(gòu)很明顯,判定一個數(shù)組是否包含某一個值。

extend
function extend(destination, source, propertiesToSkip) {
    propertiesToSkip = propertiesToSkip || [];
    for (var property in source) {
      if (!arrayContains(propertiesToSkip, property)) {
        destination[property] = source[property];
      }
    }
    return destination;
  }

此函數(shù)實(shí)現(xiàn)對象擴(kuò)展,propertiesToSkip參數(shù)為source中需排除掉的鍵,余下的鍵值對覆蓋寫入destination。

初始化語句
  if (typeof window === "undefined" && typeof exports === "object") {
    exports.MockAjax = MockAjax;
    jasmine.Ajax = new MockAjax(exports);
  } else {
    window.MockAjax = MockAjax;
    jasmine.Ajax = new MockAjax(window);
  }

首先判定是否commonjs環(huán)境,不是則傳遞window變量。在describe內(nèi)部,即可訪問通過jasmine.Ajax使用MockAjax對象。

RequestTracker

其實(shí)結(jié)構(gòu)非常明顯,使用jasmine.Ajax.requests即可訪問到RequestTracker對象,然后通過first, mostRecent, at, filter 等方法獲取仿造的request對象,多用于對HTTP請求對象進(jìn)行判定,如方法,路徑,數(shù)據(jù),headers等等,需要重點(diǎn)關(guān)注。reset, track手動調(diào)用意義不大,前者用于重置變量環(huán)境,后者在生成偽造XHR時調(diào)用。

 function RequestTracker() {
    var requests = [];

    this.track = function(request) {
      requests.push(request);
    };

    this.first = function() {
      return requests[0];
    };

    this.count = function() {
      return requests.length;
    };

    this.reset = function() {
      requests = [];
    };

    this.mostRecent = function() {
      return requests[requests.length - 1];
    };

    this.at = function(index) {
      return requests[index];
    };

    this.filter = function(url_to_match) {
      if (requests.length === 0) { return []; }
      var matching_requests = [];

      for (var i = 0; i < requests.length; i++) {
        if (url_to_match instanceof RegExp &&
            url_to_match.test(requests[i].url)) {
            matching_requests.push(requests[i]);
        } else if (url_to_match instanceof Function &&
            url_to_match(requests[i])) {
            matching_requests.push(requests[i]);
        } else {
          if (requests[i].url === url_to_match) {
            matching_requests.push(requests[i]);
          }
        }
      }
      return matching_requests;
    };
  }
StubTracker

通過jasmine.Ajax.stubs即可訪問到StubTracker對象,主動調(diào)用意義不大。reset方法用于變量環(huán)境重置,addStub方法在生成RequestStub對象時調(diào)用。findStubxhr.open()調(diào)用時,判定是否定義過response

  function StubTracker() {
    var stubs = [];

    this.addStub = function(stub) {
      stubs.push(stub);
    };

    this.reset = function() {
      stubs = [];
    };

    this.findStub = function(url, data, method) {
      for (var i = stubs.length - 1; i >= 0; i--) {
        var stub = stubs[i];
        if (stub.matches(url, data, method)) {
          return stub;
        }
      }
    };
  }
RequestStub

請求攔截在url, stubData, method同時匹配的情況下才會啟動攔截。

 function RequestStub(url, stubData, method) {
    var normalizeQuery = function(query) {
      return query ? query.split("&").sort().join("&") : undefined;
    };

    if (url instanceof RegExp) {
      this.url = url;
      this.query = undefined;
    } else {
      var split = url.split("?");
      this.url = split[0];
      this.query = split.length > 1 ? normalizeQuery(split[1]) : undefined;
    }

    this.data = normalizeQuery(stubData);
    this.method = method;

    this.andReturn = function(options) {
      this.status = options.status || 200;

      this.contentType = options.contentType;
      this.responseText = options.responseText;
    };

    this.matches = function(fullUrl, data, method) {
      var matches = false;
      fullUrl = fullUrl.toString();
      if (this.url instanceof RegExp) {
        matches = this.url.test(fullUrl);
      } else {
        var urlSplit = fullUrl.split("?"),
            url = urlSplit[0],
            query = urlSplit[1];
        matches = this.url === url && this.query === normalizeQuery(query);
      }
      return matches && (!this.data || this.data === normalizeQuery(data)) && (!this.method || this.method === method);
    };
  }
ParamParser

主要負(fù)責(zé)值的解析。paramParsers參數(shù)為parser對象數(shù)組。findParser遍歷paramParsers,通過test屬性判定是否啟用對應(yīng)的parse方法處理數(shù)據(jù)。若決定調(diào)用,則遍歷結(jié)束,返回該對象。add方法一般會通過jasmine.Ajax.addCustomParamParser(parser)調(diào)用,優(yōu)先級上,后添加的>先添加的>默認(rèn)的。

  function ParamParser() {
    var defaults = [
      {
        test: function(xhr) {
          return (/^application/json/).test(xhr.contentType());
        },
        parse: function jsonParser(paramString) {
          return JSON.parse(paramString);
        }
      },
      {
        test: function(xhr) {
          return true;
        },
        parse: function naiveParser(paramString) {
          var data = {};
          var params = paramString.split("&");

          for (var i = 0; i < params.length; ++i) {
            var kv = params[i].replace(/+/g, " ").split("=");
            var key = decodeURIComponent(kv[0]);
            data[key] = data[key] || [];
            data[key].push(decodeURIComponent(kv[1]));
          }
          return data;
        }
      }
    ];
    var paramParsers = [];

    this.add = function(parser) {
      paramParsers.unshift(parser);
    };

    this.findParser = function(xhr) {
        for(var i in paramParsers) {
          var parser = paramParsers[i];
          if (parser.test(xhr)) {
            return parser;
          }
        }
    };

    this.reset = function() {
      paramParsers = [];
      for(var i in defaults) {
        paramParsers.push(defaults[i]);
      }
    };

    this.reset();
  }
FackXMLHttpRequest

代碼過長,分段說明。

FakeXMLHttpRequest
實(shí)例化后,即添加進(jìn)入requestTracker,便于后期訪問。

function FakeXMLHttpRequest() {
  requestTracker.track(this);
  this.requestHeaders = {};
  this.overriddenMimeType = null;
}

原型繼承
此處感覺比較好玩,是繼承真的XMLHttpRequest對象,只是去掉幾個特殊鍵值對,后面會進(jìn)行處理。

var iePropertiesThatCannotBeCopied = ["responseBody", "responseText", "responseXML", "status", "statusText", "responseTimeout"];
    extend(FakeXMLHttpRequest.prototype, new window.XMLHttpRequest(), iePropertiesThatCannotBeCopied);

Request偽造
熟悉原生ajax的應(yīng)該很容易看懂。重點(diǎn)在于,send方法調(diào)用時,會立即在stubs里尋找匹配當(dāng)前url,method,data的響應(yīng)攔截器,如果預(yù)定義過了,則會立刻傳遞給response函數(shù)進(jìn)行響應(yīng),否則需要之后手動調(diào)用response函數(shù)進(jìn)行響應(yīng)。

    extend(FakeXMLHttpRequest.prototype, {

      open: function() {
        this.method = arguments[0];
        this.url = arguments[1];
        this.username = arguments[3];
        this.password = arguments[4];
        this.readyState = 1;
        this.onreadystatechange();
      },

      setRequestHeader: function(header, value) {
        if(this.requestHeaders.hasOwnProperty(header)) {
          this.requestHeaders[header] = [this.requestHeaders[header], value].join(", ");
        } else {
          this.requestHeaders[header] = value;
        }
      },

      overrideMimeType: function(mime) {
        this.overriddenMimeType = mime;
      },

      abort: function() {
        this.readyState = 0;
        this.status = 0;
        this.statusText = "abort";
        this.onreadystatechange();
      },

      readyState: 0,

      onload: function() {
      },

      onreadystatechange: function(isTimeout) {
      },

      status: null,

      send: function(data) {
        this.params = data;
        this.readyState = 2;
        this.onreadystatechange();

        var stub = stubTracker.findStub(this.url, data, this.method);
        if (stub) {
          this.response(stub);
        }
      },

      contentType: function() {
        return findHeader("content-type", this.requestHeaders);
      },

      data: function() {
        if (!this.params) {
          return {};
        }

        return paramParser.findParser(this).parse(this.params);
      },

      getResponseHeader: function(name) {
        return findHeader(name, this.responseHeaders);
      },

      getAllResponseHeaders: function() {
        var responseHeaders = [];
        for (var i in this.responseHeaders) {
          if (this.responseHeaders.hasOwnProperty(i)) {
            responseHeaders.push(i + ": " + this.responseHeaders[i]);
          }
        }
        return responseHeaders.join("
");
      },

      responseText: null,

      response: function(response) {
        if (this.readyState === 4) {
          throw new Error("FakeXMLHttpRequest already completed");
        }
        this.status = response.status;
        this.statusText = response.statusText || "";
        this.responseText = response.responseText || "";
        this.readyState = 4;
        this.responseHeaders = response.responseHeaders ||
          {"Content-Type": response.contentType || "application/json" };

        this.onload();
        this.onreadystatechange();
      },

      responseTimeout: function() {
        if (this.readyState === 4) {
          throw new Error("FakeXMLHttpRequest already completed");
        }
        this.readyState = 4;
        jasmine.clock().tick(30000);
        this.onreadystatechange("timeout");
      }
    });

    return FakeXMLHttpRequest;
  }

經(jīng)驗(yàn)交流

QQ: 491229492
Email: [email protected]

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85243.html

相關(guān)文章

  • karma-jasmine 踩坑記錄

    摘要:如有排版錯誤,請查閱官方文檔未定義昨日遇到問題,在安裝后,對應(yīng)框架未能引入,需要全局安裝后方可排除。使用單元測試中,為使用單元測試中,鏈?zhǔn)秸{(diào)用函數(shù)與最新文檔有明顯差異??偨Y(jié)來說,就是使用前,確定使用的是哪一個版本,再進(jìn)行操作。 如有排版錯誤,請查閱https://www.zybuluo.com/bornkiller/note/24702 官方文檔: jasmine : http...

    Shimmer 評論0 收藏0
  • How to Use Ext Ajax in Promise Style and Test It

    After translated a blog about how Promise works in a more functional programming way, I tried to build something to make Ext Ajax call to work in Promise style as a practice. ExtPromise is a simple w...

    whataa 評論0 收藏0
  • Flink Metrics 源碼解析

    摘要:有如下模塊源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析使用和監(jiān)控和博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自 Flink Metrics 有如下模塊: Flink Metrics 源碼解析 —— Flink-metrics-core Flink Metrics 源碼解析 —— Flink-metr...

    sshe 評論0 收藏0
  • Flink 源碼解析 —— 深度解析 Flink Checkpoint 機(jī)制

    摘要:機(jī)制博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)轉(zhuǎn)換從到學(xué)習(xí)介紹中的從到學(xué)習(xí)中的幾種詳解從到學(xué)習(xí)讀取數(shù)據(jù)寫入到從到學(xué)習(xí)項(xiàng)目如何運(yùn)行從 Flink Checkpoint 機(jī)制 https://t.zsxq.com/ynQNbeM 博客 1、Flink 從0到1學(xué)習(xí) —— Apache Fl...

    0x584a 評論0 收藏0
  • Flink 源碼解析 —— 深度解析 Flink 序列化機(jī)制

    摘要:序列化機(jī)制博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)轉(zhuǎn)換從到學(xué)習(xí)介紹中的從到學(xué)習(xí)中的幾種詳解從到學(xué)習(xí)讀取數(shù)據(jù)寫入到從到學(xué)習(xí)項(xiàng)目如何 Flink 序列化機(jī)制 https://t.zsxq.com/JaQfeMf 博客 1、Flink 從0到1學(xué)習(xí) —— Apache Flink 介紹 2...

    y1chuan 評論0 收藏0

發(fā)表評論

0條評論

劉明

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<