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 ( ...
随机推荐
- [OpenCV-Python] 15 图像阈值
文章目录 OpenCV-Python:IV OpenCV中的图像处理 15 图像阈值 15.1 简单阈值 15.2 自适应阈值 15.3 Otsu' 's 二值化 15.4 Otsu' 's 二值化是 ...
- 2022年5月5日模拟赛题解与总结(ABC237)
总结 初一第一,竞赛班第二 还可以,为了照顾提高班来的四个同学放了四个水题,可惜他们做的不是很理想,希望他们下次可以获得满意的成绩 这次做的其实是 AtCoder ABC237 A.Not Overf ...
- Java读取数据库表(二)
Java读取数据库表(二) application.properties db.driver.name=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://loc ...
- Pwn系列之Protostar靶场 Stack1题解
(gdb) disasse main Dump of assembler code for function main: 0x08048464 <main+0>: push ebp 0x0 ...
- SignalR服务端及客户端实现
服务器端: 引用nuget: 1.Microsoft.AspNet.SignalR.SelfHost 2.Microsoft.Owin.Cors internal class Program { st ...
- 关于python中的OSError报错问题
Traceback (most recent call last): File "main.py", line 1, in <module> from trai ...
- 2021-08-04:给定一个字符串str,当然可以生成很多子序列。返回有多少个子序列是回文子序列,空序列不算回文。比如,str = “aba”,回文子序列:{a}、{a}、 {a,a}、 {b}、{
2021-08-04:给定一个字符串str,当然可以生成很多子序列.返回有多少个子序列是回文子序列,空序列不算回文.比如,str = "aba",回文子序列:{a}.{a}. {a ...
- Linux 创建 Python 虚拟环境
Linux 创建 Python 虚拟环境 0. 前言 网上教程太杂太乱,要么排版不好看,要么讲半天讲不到重点,故做此篇,精简干练. 1. 安装virtualenv 先用pip安装virtualenv第 ...
- Experimental support for decorators is a feature that is subject to change in a future release. Set
错误提示Experimental support for decorators is a feature that is subject to change in a future release. ...
- css预编译sass和stylus简单使用
目前css 流行的三大预编译有stylus.less . sass 说白了这些东西就是为了提高编码效率,更好的规整和简化 css代码的,相信大家less 就不用多说了用得都比较多了,在这里简单记录下s ...