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 ( ...
随机推荐
- [Pytorch框架] 4.2.1 使用Visdom在 PyTorch 中进行可视化
文章目录 4.2.1 使用Visdom在 PyTorch 中进行可视化 安装 坑 基本概念 Environments Panes VIEW 可视化接口 使用 绘制简单的图形 更新损失函数 import ...
- 【Azure Developer】Azure AD 注册应用的 OAuth 2.0 v2 终结点获取的 Token 解析出来依旧为v1.0, 这是什么情况!
问题描述 使用 Azure AD 注册应用 Oauth2 v2.0的终结点(OAuth 2.0 token endpoint (v2):https://login.partner.microsofto ...
- Pwn系列之Protostar靶场 Stack6题解
源码如下: #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <stri ...
- #Python 缺失值的检测与处理,检测部分
Python 缺失值的检测与处理,分两部分笔记,第一部分是检测缺失值部分
- 2020-10-29:使用redis实现分布式限流组件,要求高并发场景同一IP一分钟内只能访问100次,超过限制返回异常,写出实现思路或伪代码均可。
福哥答案2020-10-29: 简单回答:固定窗口:string.key存ip,value存次数.滑动窗口:list.key存ip,value=list,存每次访问的时间. 中级回答:固定窗口:用re ...
- 分类树,我从2s优化到0.1s
前言 Java技术突击网站:http://www.susan.net.cn 分类树查询功能,在各个业务系统中可以说随处可见,特别是在电商系统中. 但就是这样一个简单的分类树查询功能,我们却优化了5次. ...
- 代码随想录算法训练营Day9|字符串KMP算法总结
代码随想录算法训练营 代码随想录算法训练营Day9字符串|KMP算法 8. 实现 strStr() 459.重复的子字符串 字符串总结 双指针回顾 28. 实现 strStr() KMP算法 题目链接 ...
- .NET 创建无边框的跨平台应用
.NET 创建无边框的跨平台应用 在创建了Photino应用程序以后我们发现它自带了一个标题栏,并且非常丑,我们现在要做的就是去掉这个很丑的自带标题栏,并且自定义一个更好看的,下面我们将用Masa B ...
- Mysql DDL执行方式-pt-osc介绍 | 京东云技术团队
1 引言 大家好,接着上次和大家一起学习了<MySQL DDL执行方式-Online DDL介绍>,那么今天接着和大家一起学习另一种MySQL DDL执行方式之pt-soc. 在MySQL ...
- 万字长文讲透 RocketMQ 4.X 消费逻辑
RocketMQ 是笔者非常喜欢的消息队列,4.9.X 版本是目前使用最广泛的版本,但它的消费逻辑相对较重,很多同学学习起来没有头绪. 这篇文章,笔者梳理了 RocketMQ 的消费逻辑,希望对大家有 ...