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

資訊專欄INFORMATION COLUMN

動(dòng)手實(shí)現(xiàn)一個(gè)JSONP

Julylovin / 1568人閱讀

摘要:但是當(dāng)我們有多個(gè)請(qǐng)求,并且每個(gè)請(qǐng)求的處理都是不一樣的時(shí)候,這個(gè)變量將會(huì)被覆蓋。這是不行的,因此我們應(yīng)該為每一次請(qǐng)求設(shè)置一個(gè)唯一且不會(huì)沖突的變量,因此增加一個(gè)生成名字的方法如下這時(shí)候我們會(huì)發(fā)現(xiàn)我們已經(jīng)利用了一個(gè)類似于隨機(jī)的形式完成了多次請(qǐng)求。

文章首發(fā)于我的github及個(gè)人博客,github請(qǐng)看https://github.com/huruji/blo...,轉(zhuǎn)載請(qǐng)注明出處。

JSONP的原理就不細(xì)說(shuō)了,就是利用script可以跨域的特點(diǎn)來(lái)實(shí)現(xiàn)跨域,首先我們考慮一個(gè)最簡(jiǎn)單的jsonp,就是簡(jiǎn)簡(jiǎn)單單創(chuàng)建script標(biāo)簽,
添加url的功能,如下:

function jsonp(url) {
  const script = document.createElement("script");
  script.src = url;
  script.type = "text/javascript";
  document.body.appendChild(script);
}

此時(shí)我們使用服務(wù)端的代碼如下:

const http = require("http");
const data = {"data":"hello"};
const url = require("url");
const queryString = require("querystring");

http.createServer(function(req, res) {
  var params = url.parse(req.url);
  console.log(params);
  if(params.query && queryString.parse(params.query).callback) {
    console.log(1231232);
    const str = queryString.parse(params.query).callback + "(" + JSON.stringify(data) + ")";
    return res.end(str)
  }
  res.end(JSON.stringify(data));
}).listen(5000);

這是我們調(diào)用jsonp,假設(shè)我們只是想要alert出返回的數(shù)據(jù),如下:

function msg(res) {
  alert(res.data);
}

jsonp("http://localhost:5000?callback=msg");

這時(shí)候我們運(yùn)行代碼可以發(fā)現(xiàn)已經(jīng)正確彈出了相應(yīng)的數(shù)據(jù)。
但是我們會(huì)發(fā)現(xiàn)這里的callback回調(diào)函數(shù)是一個(gè)全局的,這是不可取的,因此我們需要進(jìn)行一些修改,將處理修改為一個(gè)局部的,我們可以將其作為一個(gè)回調(diào)函數(shù)來(lái)處理,如下:

function jsonp(url, callback) {
  window.jsonpCallback = callback;
  const script = document.createElement("script");
  script.src = url + "?callback=jsonpCallback";
  script.type = "text/javascript";
  document.body.appendChild(script);
}

jsonp("http://localhost:5000", function(res) {
  alert(res.data);
});

這時(shí)候我們會(huì)發(fā)現(xiàn)我們不再需要在url中聲明相應(yīng)的callback了,但是我們還是會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,就是我們將所有的callback都設(shè)置成了一個(gè)全局變量,這樣的原因是因?yàn)槲覀冃枰跀?shù)據(jù)請(qǐng)求完成之后調(diào)用這個(gè)方法,因此不得不設(shè)置為一個(gè)全局變量。但是當(dāng)我們有多個(gè)請(qǐng)求,并且每個(gè)請(qǐng)求的處理都是不一樣的時(shí)候,這個(gè)變量將會(huì)被覆蓋。這是不行的,因此我們應(yīng)該為每一次請(qǐng)求設(shè)置一個(gè)唯一且不會(huì)沖突的變量,因此增加一個(gè)生成callback名字的方法如下:

function generateJsonpCallback() {
  return `jsonpcallback_${Date.now()}_${Math.floor(Math.random() * 100000)}`;
}

function jsonp(url, callback) {
  const funcName = generateJsonpCallback();
  window[funcName] = callback;
  const script = document.createElement("script");
  script.src = `${url}?callback=${funcName}`;
  script.type = "text/javascript";
  document.body.appendChild(script);
}


jsonp("http://localhost:5000", function(res) {
  alert(res.data);
});

jsonp("http://localhost:5000", function(res) {
  const text = document.createTextNode(res.data);
  document.body.appendChild(text);
});

這時(shí)候我們會(huì)發(fā)現(xiàn)我們已經(jīng)利用了一個(gè)類似于隨機(jī)ID的形式完成了多次請(qǐng)求。
但是還是有一個(gè)問(wèn)題大量的請(qǐng)求之后,window中會(huì)含有大量的全局變量,而且還有大量的script標(biāo)簽,這顯然不是我們想要的,所以我們可以在請(qǐng)求完成之后刪除變量和script標(biāo)簽。

function generateJsonpCallback() {
  return `jsonpcallback_${Date.now()}_${Math.floor(Math.random() * 100000)}`;
}

function removeScript(id) {
  document.body.removeChild(document.getElementById(id));
}

function removeFunc(name) {
  delete window[name];
}

function jsonp(url, timeout = 3000, callback) {
  const funcName = generateJsonpCallback();
  window[funcName] = callback;
  const script = document.createElement("script");
  script.src = `${url}?callback=${funcName}`;
  script.id = funcName;
  script.type = "text/javascript";
  document.body.appendChild(script);
  setTimeout(() => {
    removeScript(funcName);
    removeFunc(funcName);
  }, timeout)
}


jsonp("http://localhost:5000", 3000, function(res) {
  alert(res.data);
});

jsonp("http://localhost:5000", 3000, function(res) {
  const text = document.createTextNode(res.data);
  document.body.appendChild(text);
});

我們通過(guò)將利用一個(gè)timeout時(shí)間定時(shí)為我們清除相應(yīng)的script標(biāo)簽和全局變量就可以了,這個(gè)定時(shí)時(shí)間的作用類似于ajax的timeout時(shí)間。
我們所有的內(nèi)容都是使用es6的,那為什么不使用Promise來(lái)處理呢,還要使用煩人的回調(diào),接下來(lái)那就來(lái)Promise化吧。

function jsonp(url, options = {timeout:3000}) {
  const timeout = options.timeout;
  return new Promise((resolve, reject) => {
    const funcName = generateJsonpCallback();
    window[funcName] = (res) => {
      resolve(res);
      setTimeout(() => {
        removeScript(funcName);
        removeFunc(funcName);
      }, timeout)
    };
    const script = document.createElement("script");
    script.src = `${url}?callback=${funcName}`;
    script.id = funcName;
    script.type = "text/javascript";
    document.body.appendChild(script);
  })
}

調(diào)用只需要如下就可以了

jsonp("http://localhost:5000").then((res) => alert(res.data));

jsonp("http://localhost:5000").then((res) => {
  const text = document.createTextNode(res.data);
  document.body.appendChild(text);
});

到目前為止,一個(gè)較為完整的jsonp就實(shí)現(xiàn)了,但是我們還是會(huì)覺得少了一些什么,相信你已經(jīng)看出來(lái)了,那就是錯(cuò)誤處理。
迄今為止,并沒有測(cè)試過(guò)如果這個(gè)script標(biāo)簽加載不成功如何處理,判斷資源加載失敗,顯然使用的是onerror事件,我們這就把他加上:

function jsonp(url, options = {timeout:3000}) {
  const timeout = options.timeout;
  let timeId;
  return new Promise((resolve, reject) => {
    const funcName = generateJsonpCallback();
    window[funcName] = (res) => {
      resolve(res);
      timeId = setTimeout(() => {
        removeScript(funcName);
        removeFunc(funcName);
      }, timeout)
    };
    const script = document.createElement("script");
    script.src = `${url}?callback=${funcName}`;
    script.id = funcName;
    script.type = "text/javascript";
    document.body.appendChild(script);
    script.onerror = () => {
      reject(new Error(`fetch ${url} failed`));
      removeScript(funcName);
      removeFunc(funcName);
      if(timeId) clearTimeout(timeId);
    }
  })
}

我們可以測(cè)試一下,輸入一個(gè)不存在的url:

jsonp("http://localhost:7000").then((res) => alert(res.data));

可以發(fā)現(xiàn)這時(shí)正常處理錯(cuò)誤了,可以在控制臺(tái)看到相應(yīng)的url獲取失敗,至此,完工;

至此所有的代碼簡(jiǎn)單封裝如下:

(function(global){
  function generateJsonpCallback() {
    return `jsonpcallback_${Date.now()}_${Math.floor(Math.random() * 100000)}`;
  }

  function removeScript(id) {
    document.body.removeChild(document.getElementById(id));
  }

  function removeFunc(name) {
    delete global[name];
  }

  function jsonp(url, options = {timeout:3000}) {
    const timeout = options.timeout;
    let timeId;
    return new Promise((resolve, reject) => {
      const funcName = generateJsonpCallback();
      global[funcName] = (res) => {
        resolve(res);
        timeId = setTimeout(() => {
          removeScript(funcName);
          removeFunc(funcName);
        }, timeout)
      };
      const script = document.createElement("script");
      script.src = `${url}?callback=${funcName}`;
      script.id = funcName;
      script.type = "text/javascript";
      document.body.appendChild(script);
      script.onerror = () => {
        reject(new Error(`fetch ${url} failed`));
        removeScript(funcName);
        removeFunc(funcName);
        if(timeId) clearTimeout(timeId);
      }
    })
  }
  window.jsonp = jsonp;
})(window);

測(cè)試代碼如下:

jsonp("http://localhost:5000").then((res) => alert(res.data));

jsonp("http://localhost:5000").then((res) => {
  const text = document.createTextNode(res.data);
  document.body.appendChild(text);
});

jsonp("http://localhost:7000").then((res) => alert(res.data));

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

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

相關(guān)文章

  • 自己動(dòng)手,為vue寫一個(gè)jsonp的方法

    摘要:它之后能夠被使用到很多場(chǎng)景中其他處理請(qǐng)求和響應(yīng)的方式,甚至任何需要生成自己的響應(yīng)的方式。總結(jié)到這里都講完了,其實(shí)沒什么難度,主要是自己項(xiàng)目中遇到了,但是中沒有這個(gè)方法啊。所以就想著實(shí)現(xiàn)了一個(gè),因?yàn)槠渌姆椒ㄒ捕挤庋b,不差這一個(gè)了。 Fetch 提供了對(duì)?Request?和?Response?(以及其他與網(wǎng)絡(luò)請(qǐng)求有關(guān)的)對(duì)象通用的定義。它之后能夠被使用到很多場(chǎng)景中:service wor...

    dongxiawu 評(píng)論0 收藏0
  • jsonp的原理介紹及Promise封裝

    摘要:什么叫是填充式或參數(shù)式的簡(jiǎn)寫,是通過(guò)請(qǐng)求跨域接口,獲取數(shù)據(jù)的新實(shí)現(xiàn)方式的實(shí)現(xiàn)原理動(dòng)態(tài)創(chuàng)建標(biāo)簽,因?yàn)闃?biāo)簽是沒有同源策略限制,可以跨域的。具體看接下來(lái)的實(shí)現(xiàn)這個(gè)是庫(kù)的具體實(shí)現(xiàn),建議下載來(lái)研究一下,最好自己動(dòng)手寫一遍。 什么叫jsonp? jsonp是json with padding(填充式j(luò)son或參數(shù)式j(luò)son)的簡(jiǎn)寫,是通過(guò)ajax請(qǐng)求跨域接口,獲取數(shù)據(jù)的新實(shí)現(xiàn)方式 jsonp的實(shí)現(xiàn)...

    ninefive 評(píng)論0 收藏0
  • 想知道jsonp到底是怎么實(shí)現(xiàn)的?看我,包教會(huì)!

    摘要:不管你好不好,反正我是番茄醬。例如我們要請(qǐng)求的地址是獲取用戶信息后臺(tái)應(yīng)該返回給我們的數(shù)據(jù)是番茄醬也就是說(shuō)我們最終需要的是服務(wù)器把格式的數(shù)據(jù)給我們。于是后臺(tái)返回給我們番茄醬于是代碼就相當(dāng)于是番茄醬最終結(jié)果與相同。 不管你好不好,反正我是番茄醬。為啥要寫這篇文章呢,因?yàn)槲蚁雽憽?showImg(https://segmentfault.com/img/remote/146000001846...

    Edison 評(píng)論0 收藏0
  • 基于Vue.js的音樂(lè)播放器(Webapp)

    摘要:概述項(xiàng)目是基于,成品是一個(gè)移動(dòng)端的音樂(lè)播放器,來(lái)源于的實(shí)戰(zhàn)課程。播放器是全局組件,放在下面,通過(guò)傳遞數(shù)據(jù),觸發(fā)提交,從而使播放器開始工作。將請(qǐng)求的數(shù)據(jù)格式化后再通過(guò)傳遞,組件間共享,實(shí)現(xiàn)歌曲的播放切換等。 概述 項(xiàng)目是基于Vue.js,成品是一個(gè)移動(dòng)端的音樂(lè)播放器,來(lái)源于imooc的實(shí)戰(zhàn)課程。自己動(dòng)手實(shí)踐并加以修改拓展。項(xiàng)目的大致流程是Vue-cli構(gòu)建開發(fā)環(huán)境,分析需求,設(shè)計(jì)構(gòu)思,規(guī)...

    widuu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<