JSONP前端流程
JSONP前端流程
JSONP总体思路
- 后端先给前端一个接口文档。
- 如
https://www.baidu.com/sugrec?prod=pc&wd=用户输入的文字&cb=后端要调用的前端定义的全局函数名。
- 如
- 前端会封装一个jsonp函数:它的作用是传入特定参数,返回一个Promise实例。
会用jsonp的方式来请求后端数据,把后端数据通过Promise实例返回。
- 此时这个Promise实例的状态为"pending"。
它内部会创建一个
临时的唯一方法名如jQuery_202301010101。并自动生成一个全局函数,该函数的功能就是把传入的入参resolve()出去。window[`jQuery_202301010101`] = function (data) {
resolve(data); //把data传递给了resolve函数,也就是传递给了成功的回调函数,所以jsonp后面的then就会执行了。
}
并把这个
临时的唯一方法名通过构建一个script标签通过get发送请求传递给后端。之后后端会返回一段动态的js代码,如
临时的唯一方法名(前端想要的数据)如jQuery_202301010101({name:'6666',list:[{id:1,text:'文字1'},{id:2,text:'文字2'}]})。浏览器会把后端返回的
jQuery_202301010101({name:'6666',list:[{id:1,text:'文字1'},{id:2,text:'文字2'}]})当成js代码在全局作用域中执行。jQuery_202301010101({name:'6666',list:[{id:1,text:'文字1'},{id:2,text:'文字2'}]})
//相当于:window[`jQuery_202301010101`]({name:'6666',list:[{id:1,text:'文字1'},{id:2,text:'文字2'}]})
window[`jQuery_202301010101`] = function (data) {
resolve(data); //把data传递给了resolve函数,也就是传递给了成功的回调函数,所以jsonp后面的then就会执行了。
}
此时这个Promise实例的状态为"fulfilled",值就为后端要返回的json数据,如
{name:'6666',list:[{id:1,text:'文字1'},{id:2,text:'文字2'}]}。
- 用户触发事件,会调用jsonp函数,得到一个Promise实例。此时代码就执行到了jsonp函数中。
- 一开始这个Promise实例的状态为"pending",在后端返回一段动态的js代码并在浏览器中执行后,该Promise实例的状态就变成"fulfilled",同时then()中得到的结果值就是后端返回的json数据。
- Promise实例的状态变成"fulfilled"后,通过then()拿到后端返回的json数据,如
{name:'6666',list:[{id:1,text:'文字1'},{id:2,text:'文字2'}]},并重新渲染页面。
代码说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input id="search-word" />
<ul id="suggestions"></ul>
<script>
function jsonp(options) {
return new Promise((resolve, reject) => {
const { url, jsonp, data } = options;
let callbackName = `jQuery_${Date.now()}`; //1.或者创建一个临时的、唯一的方法名。
//给window添加一个全局变量,变量名为方法名,值是一个只会给后端调用一次的函数。
window[callbackName] = function (data) {
delete window[callbackName];
document.body.removeChild(script);
resolve(data); //把data传递给了resolve函数,也就是传递给了成功的回调函数,所以jsonp后面的then就会执行了。
};
//动态创建一个类型为script的对象或者说元素
let script = document.createElement("script");
let queryStr = url.indexOf("?") === -1 ? "?" : "&";
for (let key in data) {
queryStr += `${key}=${data[key]}&`;
}
script.src = `${url}${queryStr}${jsonp}=${callbackName}`; //得到一个url地址。
script.onerror = (error) => reject(error);
document.body.appendChild(script); //向body的尾部添加一个script对象,之后浏览器就会向服务器发起一个get请求。请求回来的其实是字符串,但浏览器会把那些字符串当成js代码来执行。//后端返回的数据格式为:前端传递给的函数名(前端想要的数据对象) 如:jQuery_998888({name:'前端想要的数据',...}) //浏览器在拿到这个后端返回的数据后,就相当于在全局作用域下运行了一遍后端的代码。
});
}
let searchWord = document.getElementById("search-word");
let suggestions = document.getElementById("suggestions");
const handleInput = (event) => {
let wd = event.target.value;
const thePromise = jsonp({
url: "https://www.baidu.com/sugrec", //也可能为https://www.baidu.com/sugrec?prod=pc
jsonp: "cb", //百度的后端规定了这个字段就叫cb。但网易的可能的约定为callback或者cbf之类的,反正是后端规定的。
data: { prod: "pc", wd }, //其它要传递给服务器的数据,它们都会拼接到查询字符串中。这个有些字段是前端定的,有些字段是后端定的。
});
thePromise
.then((result) => {
//这个就是后端返回的 jQuery_998888({name:'前端想要的数据',...}) 中的 {name:'前端想要的数据',...}。
let { g } = result;
if (g) {
0;
let html = "";
for (let i = 0; i < g.length; i++) {
html += `<li>${g[i].q}</li>`;
}
suggestions.innerHTML = html;
}
})
.catch((error) => {
console.log(error);
});
};
searchWord.addEventListener("input", handleInput);
</script>
</body>
</html>
前后端交互模板
- fang/f20230731/1.basic/doc/jsonp.html 这个就是前端写的代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>jsonp</title>
</head>
<body>
动态jsonp。这里是自动生成的`Live Server`起起来的;
<script>
let callbackName = `JQuery_${Date.now()}`;
console.log(`动态函数变量名:callbackName-->`, callbackName);
window[callbackName] = async (data) => {
console.log(`后端返回的json数据:data-->`, data);
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data666);
}, 300000);
});
// 执行结束后,移除多余代码。
console.log(`执行结束后,移除多余代码。`);
window[callbackName] = null;
document.body.removeChild(script);
};
let script = document.createElement("script");
script.src = `http://localhost:8111/sugrec.js?cb=${callbackName}`;
console.log(`动态生成的脚本标签:script-->`, script);
document.body.appendChild(script);
</script>
</body>
</html>
- fang/f20230731/1.basic/doc/jsonp.js 这个是后端服务器的代码。
// 这里是用node起起来的,服务器端口为8111;
const http = require('http')
const url = require('url')
http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/javascript')
const { query: { cb } } = url.parse(req.url || '', true)//这里是为了让后端拿到前端定义的那个函数的函数名。
console.log(`cb-->`, cb);//这里是在命令行中打印的。
const jsonObj = { 'id': 100, name: '这个是后端构建出来的json数据' }//这个就是后端要返回的json数据。
//let script = `${cb}(${jsonStr})`//实际上大多数的jsonp交互中,后端返回的代码就是这个格式。
const jsonStr = JSON.stringify(jsonObj)
let script = `
// 这里是服务器那边动态生成的js代码。
console.log('开始执行服务器返回的动态js代码。')
${cb}(${jsonStr});
console.log('结束执行服务器返回的动态js代码。')
`
res.end(script);
}).listen(8111, () => {
console.log(`服务器地址为: http://localhost:8111`);
})
进阶参考
JSONP前端流程的更多相关文章
- 亚信UED前端流程自动化构建工具
亚信UED前端流程自动化构建工具 .wmd-input, .wmd-input:focus, #md-section-helper {font-size: 14px !important;line-h ...
- 微信小程序支付功能前端流程
只是分享一下小程序支付功能的前端流程和代码, 仅供参考(使用的是uni app). handleCreate () { /** 第一步:前台将商品数据发送到后台,后台创建订单入库并返回订单id等信息 ...
- 新手学习WEB前端流程以及学习中常见的误区
学习web前端编程技术肯定是以就业拿到高薪工作为主要目的的,可是高薪不会那么轻易拿到,这是一个最简单的道理.没有付出就没有回报,在整个学习web前端编程技术的过程中,你需要付出时间.精力.金钱.废话不 ...
- 如何正确学习web前端流程以及如何找工作
解释一下web前端工作是做啥的,Web前端开发工程师,主要职责是利用(X)HTML/CSS/JavaScript/Flash等各种Web技术进行客户端产品的开发.完成客户端程序(也就是浏览器端)的开发 ...
- Django 项目补充知识(JSONP,前端瀑布流布局,组合搜索,多级评论)
一.JSONP 1浏览器同源策略 通过Ajax,如果在当前域名去访问其他域名时,浏览器会出现同源策略,从而阻止请求的返回 由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一 ...
- 从0搭建Vue3组件库(六):前端流程化控制工具gulp的使用
前言 随着前端诸如webpack,rollup,vite的发展,gulp感觉似乎好像被取代了.其实并没有,只不过它从台前退居到了幕后.我们仍然可以在很多项目中看到它的身影,比如elementplus. ...
- Gulp常用前端流程自动化配置
前言 近期的项目全部由Grunt + LESS 转向改用Gulp + SASS 进行前端开发,也就奔着Gulp那比较好用的自定义函数而来的. 一.package.json文件配置如下: { " ...
- GruntJS常用前端流程自动化配置-【持续优化】
前言 近期用Grunt进行前端开发经常要用到的一些Grunt插件,用起来非常顺手. 一.package.json文件配置如下: 包括coffeescript编译为js,css加CSS3适配前缀,css ...
- svn迁移gitlab,构建前端打包发布流程
前端资源迁移 目前公司的前端资源托管在svn服务器上,由于团队的逐渐扩大,svn的分支管控越来越不灵活,而且对于以后前端流程一体化的处理支持不是很好,因此决定在版本控制上转向git.git的好 ...
- 前端工程化开发之yeoman、bower、grunt
上两遍文章介绍了前端模块化开发(以seaJs为例)和前端自动化开发(以grunt为例)的流程,参见: http://www.cnblogs.com/luozhihao/p/4818782.html ( ...
随机推荐
- Swift下Data处理全流程:从网络下载,数模转换,本地缓存到页面使用
Swift下将网络返回json数据转换成struct 假如网络请求返回的数据结构是一个深层嵌套的Json 首先要通过key-value取出这个json中的数据源 // 将返回的json字符串转Dict ...
- 2021-09-03:直线上最多的点数。给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。力扣149。
2021-09-03:直线上最多的点数.给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点.求最多有多少个点在同一条直线上.力扣149. 福大大 ...
- 记一次排查:接口返回值写入excel后,从单元格copy出来的数据会带有多重引号的问题
在项目里刚好有3个服务,同一个网关内层的3个服务,两个php的,一个golang的,为了提高负载以及进行分流,部分客户的接口调用会被网关自动分配到go服务. 恰好为了测试,我写了一个全量用户的生产.测 ...
- Transformer 估算 101
本文主要介绍用于估算 transformer 类模型计算量需求和内存需求的相关数学方法. 引言 其实,很多有关 transformer 语言模型的一些基本且重要的信息都可以用很简单的方法估算出来.不幸 ...
- 2013年蓝桥杯C/C++大学B组省赛真题(第39级台阶)
题目描述: 小明刚刚看完电影<第39级台阶>,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级! 站在台阶前,他突然又想着一个问题: 如果我每一步只能迈上1个或2个台阶.先迈左脚,然 ...
- ol设置最佳可视范围和限制缩放
目前随着科技发展,智慧城市的不断发展,GIS方面的技术也是层出不穷,如市场流行的 OPENLAYERS, CESIUM, THREE等,但是也会有很多棘手的问题,比如不同分辨率下,图层的显示范围,禁止 ...
- celery笔记二之建立celery项目、配置及几种加载方式
本文首发于公众号:Hunter后端 原文链接:celery笔记二之建立celery项目.配置及几种加载方式 接下来我们创建一个 celery 项目,文件夹及目录如下: proj/__init__.py ...
- P3498 [POI2010]KOR-Beads 题解
前言: 最近在做哈希的题,发现了这道好题,看题解里很多大佬的方法都很巧妙,自己就发一个较为朴素的方法吧. 题意: 题目传送门 给你一个序列,需要求出数 k,使划分的子串长度为 k 时,不同的子串数量最 ...
- binfmt_misc
一:binfmt_misc是什么 binfmt_misc是内核中的一个功能,它能将非本机的二进制文件与特定的解析器自动匹配起来,进行二进制解析. 例如,在x86上解析arm64架构的二进制. 通过bi ...
- 【Netty】03-进阶
三. Netty 进阶 1. 粘包与半包 1.1 粘包现象 服务端代码 public class HelloWorldServer { static final Logger log = Logger ...