1. 程式人生 > 實用技巧 >Promise封裝Ajax

Promise封裝Ajax

首先我們要知道跨域是什麼,又為什麼要有跨域操作

跨域是什麼

跨域,是指瀏覽器不能執行其他網站的指令碼。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實施的安全限制。

好這裡我們提煉出兩個東西---1.同源策略:url首部的協議+域名+埠號必須一樣,一者不同即為跨域

2.安全限制(這也是為什麼需要跨域操作下一段介紹)

為什麼需要跨域操作/為啥需要同源策略/為什麼要限制ajax跨域(面試可能會這樣問)

這個和cookie的儲存原理有關(這裡不介紹cookie),在生活裡我們登入一個網站P(photoshop學習網站),然後他會存個通行證,下一次我們再上p站的時候

它是不是就自動登入了,我們用別的網站去請求登入p是不是就登入不上。

然後這個例子我們把它專業化一下下

1.客戶向p網站的伺服器傳送登入請求,攜帶賬號密碼資料

2.P網站的伺服器校驗賬號密碼正確後,返回響應並給本地添加了Cookie

3.之後客戶再次向A網站發起請求會自動帶上A網站儲存在本地的cookie

4.P網站的伺服器從cookie中獲取賬號密碼資料後,返回登陸成功介面。

假如ajax請求可以跨域,那我是不是可以在這個部落格裡寫一段js,使用ajax向你的學習網站發起登入請求,因為

很多人的電腦上會存有學習網站的cookie不需要輸入賬號密碼直接就自動登入了,再ajax回撥函式中解析了返回的資料,

我就能知道你學的是不是potoshop了。

所以才需要同源策略,為了使用者的資訊保安也必須限制ajax的跨域操作

ps:同源策略限制內容:(1)儲存內容:cookie,localStorage,sessionStorage,(2)DOM節點

(3)ajax請求,需注意ajax請求會發送出去,也會被返回,但會被瀏覽器攔截。

不被限制的有img link script

進入正題jsonp

我們現在已經知道了能夠不被同源限制的標籤有img link script 那我們該選擇哪個嘞?

當然是script,只有這兄弟和程式碼有關嘛

首先咱得整個伺服器出來用 node模擬一下

//服務端
const http =require("http");//匯入http模組
http.createServer(
    (req,res) =>
    {
      let weather="四川 梅雨天";//客戶端要訪問的資料
      res.writeHead(200,{
        "Content-Type":"text/plain;charset=utf-8"
      });//防止亂碼,用jq的Ajax就不需要,Ajax會自動識別
      res.write(weather);
      res.end();
})
.listen(3000);//3000埠

然後在客戶端寫<script src="http://localhost:3000",會得到一個型別錯誤,因為js沒法解析四川 梅雨天呀,這玩意兒都不是個語句,它笨解析不了

也就是說我們要在res.write拼接一條語句傳給客戶端於是乎

//服務端
const http =require("http");
http.createServer(
    (req,res) =>
    {
      let weather="四川 梅雨天";
      res.writeHead(200,{
        "Content-Type":"text/plain;charset=utf-8"
      });
      res.write(`("document.write(${weather}")`);
      res.end();
})
.listen(3000);

然後再在客戶端寫<script src="http://localhost:3000",就發現頁面上能打印出四川 梅雨天了,可是有個問題,我們的操作是不是寫死了?那咱就在

客戶端整個操作有關的函式唄

  function  show(w) {
   alert(w);
  }
</script>

然後把伺服器的res.write(`("document.write(${weather}")`);改成res.write(`("show(${weather}")`);嗯~ o(* ̄▽ ̄*)o可是又有問題了我要是想改函式是不是要改兩個地方

可不可以把這個函式整成動態的?可以的我們把函式的資訊放到url的query裡

<script src="http://localhost:3000?callback=show">
/*這裡用callback接受函式資訊,又因為本來show就是回撥函式(相信大家體會出來了)所以用的callback命名,愛用啥都可以*/

那麼在伺服器咋個取得callbck嘞

onst http =require("http");
const url=require("url");//引入url模組
http.createServer(
    (req,res) =>
    {
      var Url=url.parse(req.url,true);
      var callback=Url.query.callback;//大概意思從url取到callback
      let weather="四川 梅雨天";
      res.writeHead(200,{
        "Content-Type":"text/plain;charset=utf-8"
      });
      res.write(`${callback}("${weather}")`);
      res.end();
    })
    .listen(3000);

然後這個問題也解決了,但我們平時點一個按鈕然後做跨域請求肯定不是這樣把script標籤寫在外面浪費記憶體不說,程式碼還不美觀

所以終極的程式碼來了

//客戶端程式碼
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<button>天氣預報</button>
<script>
  let click=document.querySelector("button");
  click.addEventListener("click",()=>{
    let script=document.createElement("script");
    script.src=`http://localhost:3000/?callback=show`;
    document.body.appendChild(script)
  });//對按鈕新增點選事件在body裡生產script
  function  show(w) {
    alert(w);
    document.body.lastChild.remove();//對每次生成的script在結束後移除
  }
</script>
</body>
</html>
//伺服器程式碼不變

好了以上就是jsonp的原理總結一下,(1)宣告一個回撥函式,其函式名(如show)當做引數值,要傳遞給跨域請求資料的伺服器,

函式形參為要獲取目標資料(伺服器返回的data)。

(2)建立一個<script>標籤,把那個跨域的API資料介面地址,賦值給script的src,

還要在這個地址中向伺服器傳遞該函式名(可以通過問號傳參:?callback=show)。

(3)伺服器接收到請求後,需要進行特殊的處理:把傳遞進來的函式名和它需要給你的資料拼接成一個字串,

(4)最後伺服器把準備的資料通過HTTP協議返回給客戶端,客戶端再呼叫執行之前宣告的回撥函式(show),

對返回的資料進行操作

所以jsonp是一種思想每個人寫的jsonp可能都會不一樣,但終終極方案JQubiery裡ajax請求裡寫dataType:"jsonp",完事兒了,但思想還是要理解的。