Promise 详解(原理篇)
目录
什么是 Promise
实现一个 Promise
Promise 的声明
解决基本状态
添加 then 方法
解决异步实现
解决链式调用
完成 resolvePromise 函数
解决其他问题
添加 catch 方法
添加 finally 方法
添加 resolve、reject、race、all 等方法
如何验证我们的 Promise 是否正确?
什么是 Promise
Promise 是一种异步编程的解决方案。在异步操作中,callback 会导致回调地狱的问题,Promise 解决了这个问题。
一个 Promise对象有以下三种状态:
- pending:初始状态,既不是成功,也不是失败状态。
- fulfilled(resolved):意味着操作成功完成。
- rejected:意味着操作失败。
Promise对象内部运行的一个变化, 变化如下:
- 当 new Promise() 被实例化后,即表示 Promise 进入 pending 初始化状态,准备就绪,等待运行。
- 一旦 Promise 实例运行成功或者失败之后,实例状态就会变为 fulfilled 或者 rejected,此时状态就无法变更。
在使用 Promise 时,通常会调用其 then() 方法来处理异步操作的结果,或者调用 catch() 方法来处理出错信息。同时,Promise 还提供了一些静态方法,如 Promise.resolve()、Promise.reject() 等用于快速创建一个 Promise 实例。
实现一个 Promise
(下文所指的规定是指 Promise A+规范)
Promise 的声明
首先呢,promise 肯定是一个类,我们就用 class 来声明。
- 由于 new Promise((resolve, reject)=>{}) ,所以传入一个参数(函数 executor),传入就执行
- executor 里面有两个参数,一个叫 resolve(成功),一个叫 reject(失败)
- 由于 resolve 和 reject 可执行,所以都是函数,我们用 let 声明
class myPromise{// 构造器constructor(executor){// 成功let resolve = () => { };// 失败let reject = () => { };// 立即执行executor(resolve, reject);}
}
解决基本状态
Promise 有规定:
- Promise 存在三个状态(state)pending、fulfilled、rejected
- pending(等待态)为初始态,并可以转化为 fulfilled(成功态)和 rejected(失败态)
- 成功时,不可转为其他状态,且必须有一个不可改变的值(value)
- 失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)
- new Promise((resolve, reject)=>{resolve(value)}) resolve 为成功,接收参数 value,状态改变为 fulfilled,不可再次改变。
- new Promise((resolve, reject)=>{reject(reason)}) reject 为失败,接收参数 reason,状态改变为 rejected,不可再次改变。
- 若是 executor 函数报错 直接执行 reject();
于是乎,我们获得以下代码
class myPromise {constructor(executor) {// 初始化 state 为等待态this.state = 'pending'// 成功的值this.value = undefined// 失败的原因this.reason = undefinedlet resolve = value => {// state 改变 resolve 调用就会失败if (this.state === 'pending') {// resolve 调用后 state 转化为成功态this.state = 'fulfilled'}// 储存成功的值this.value = value}let reject = reason => {// state 改变 reject 调用就会失败if (this.state === 'pending') {// reject 调用后 state 转化为失败态this.state = 'rejected'}// 储存失败的原因this.reason = reason}// 立即执行 executor,如果 executor 执行报错,直接执行 rejecttry {executor(resolve, reject)} catch(err) {reject(err)}}
}
添加 then 方法
Promise 有一个叫做 then 的方法,里面有两个参数:onFulfilled 和 onRejected,成功有成功的值,失败有失败的原因
- 当状态 state 为 fulfilled,则执行 onFulfilled,传入 this.value。
- 当状态 state 为 rejected,则执行 onRejected,传入 this.reason
- onFulfilled 和 onRejected 如果是函数,则必须分别在 fulfilled,rejected 后被调用,value 或reason 依次作为他们的第一个参数
class myPromise {constructor(executor){...}// then 方法有两个参数 onFulfilled 和 onRejectedthen(onFulfilled, onRejected) {// 状态为 fulfilled,执行 onFulfilled,传入成功的值if (this.state === 'fulfilled') {onFulfilled(this.value)}// 状态为 rejected,执行 onRejected,传入失败的原因if (this.state === 'rejected') {onRejected(this.reason)}}
}
解决异步实现
现在基本可以实现简单的同步代码,但是当 resolve 在 setTomeout 内执行,调用 then 时 state 还是 pending 等待态,我们就需要在 then 调用的时候,将成功和失败存到各自的数组,一旦 reject 或者 resolve,就调用它们
类似于发布订阅,先将 then 里面的两个函数储存起来,由于一个 promise 可以有多个 then,所以存在同一个数组内。
// 多个 then 的情况
let p = new Promise();
p.then();
p.then();
成功或者失败时,forEach 调用它们
class myPromise {constructor(executor) {this.state = 'pending'this.value = undefinedthis.reason = undefined// 成功存放的数组this.onResolvedCallbacks = []// 失败存放的数组this.onRejectedCallbacks = []let resolve = value => {if (this.state === 'pending') {this.state = 'fulfilled'}this.value = value// 一旦 resolve 执行,调用成功数组的函数this.onResolvedCallbacks.forEach(fn => fn());}let reject = reason => {if (this.state === 'pending') {this.state = 'rejected'}this.reason = reason// 一旦 reject 执行,调用失败数组的函数this.onRejectedCallbacks.forEach(fn => fn())}try {executor(resolve, reject)} catch(err) {reject(err)}}then(onFulfilled, onRejected) {if (this.state === 'fulfilled') {onFulfilled(this.value)}if (this.state === 'rejected') {onRejected(this.reason)}// 状态为 pending 时if (this.state === 'pending') {// onFulfilled 传入到成功数组this.onResolvedCallbacks.push(() => onFulfilled(this.value))// onRejected 传入到失败数组this.onRejectedCallbacks.push(() => onRejected(this.reason))}}
}
解决链式调用
我门常常用到 new Promise().then().then(),这就是链式调用,用来解决回调地狱
- 为了达成链式,我们默认在第一个 then 里返回一个 promise。规定了一种方法,就是在then 里面返回一个新的 promise 称为 promise2
let promise2 = new Promise((resolve, reject)=>{}) 1. 将这个 promise2 返回的值传递到下一个 then 中 2. 如果返回一个普通的值,则将普通的值传递给下一个 then 中
- 当我们在第一个 then 中 return 了一个参数(参数未知,需判断)。这个 return 出来的新的promise 就是 onFulfilled() 或 onRejected() 的值
规定 onFulfilled() 或 onRejected() 的值,即第一个 then 返回的值,叫做 x,判断 x 的函数叫做 resolvePromise
class myPromise {constructor(executor){...}then(onFulfilled, onRejected) { // 声明返回的 promise2let promise2 = new myPromise((resolve, reject) => {if (this.state === 'fulfilled') {let x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject)}if (this.state === 'rejected') {let x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject)}if (this.state === 'pending') {this.onResolvedCallbacks.push(() => {let x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject)})this.onRejectedCallbacks.push(() => {let x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject)})}})// 返回 Promise,完成链式return promise2}
}
完成 resolvePromise 函数
规定了一段代码,让不同的 promise 代码互相套用,叫做 resolvePromise
- 如果 x === promise2,会造成循环引用,自己等待自己完成,则报“循环引用”错误
let p = new Promise(resolve => {resolve(0); }); var p2 = p.then(data => {// 循环引用,自己等待自己完成,一辈子完不成return p2; })
- x 不能是 null
- x 是普通值,直接 resolve(x)
- x 是对象或者函数(默认 promise), let then = x.then
- 如果取 then 报错,则走 reject()
- 如果 then 是个函数,则用 call 执行 then,第一个参数是 x,后面是成功的回调和失败的回调
- 如果成功的回调还是 pormise,就递归继续解析
- 因为成功和失败只能调用一个,所以设定一个 called 来防止多次调用
// 处理 x 的值,如果是普通值直接返回,如果是 promise 则返回 x.then 执行的结果
function resolvePromise(promise2, x, resolve, reject) {// 如果 new 出来的 Promise2 和 x 是同一个,循环引用报错if (promise2 === x) return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));// 先判断是不是对象或者函数if (x !== null && (typeof x === 'object' || typeof x === 'function')) {// 调用了成功就不能失败,调用了失败就不能成功,不能多次调用成功或者失败let called// 内部可能抛出错误try {// 声明 then = x 的 then 方法let then = x.then// 如果 then 是函数,就默认是 promise 了if (typeof then === 'function') {this.call(x, res => {// 成功和失败只能调用一个if (called) returncalled = true// res 可能是一个 promise,递归调用 resolvePromise,直到解析出的值是普通值resolvePromise(promise2, res, resolve, reject)}, err => {// 成功和失败只能调用一个if (called) returncalled = true// 直接调用 reject 作为失败的结果,并向下传递reject(err)})} else {// 如果 then 不是函数,就说明是个普通值,直接返回 xresolve(x)}} catch(err) {// 也属于失败,成功和失败只能调用一个if (called) returncalled = true// 直接调用 reject 作为失败的结果,并向下传递reject(err)}} else {// x 是普通值,直接返回resolve(x)}
}
解决其他问题
- 规定 onFulfilled 和 onRejected 都是可选参数,如果他们不是函数,必须被忽略
- onFulfilled 返回一个普通的值,成功时直接等于 value => value
- onRejected 返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个 then 中的 onFulfilled 中,所以直接扔出一个错误 reason => throw err
- 规定 onFulfilled 或 onRejected 不能同步被调用,必须异步调用。我们就用 setTimeout 解决异步问题
- 如果 onFulfilled 或 onRejected 报错,则直接返回 reject()
class myPromise {constructor(executor) {this.state = 'pending'this.value = undefinedthis.reason = undefinedthis.onResolvedCallbacks = []this.onRejectedCallbacks = []let resolve = value => {if (this.state === 'pending') {this.state = 'fulfilled'}this.value = valuethis.onResolvedCallbacks.forEach(fn => fn());}let reject = reason => {if (this.state === 'pending') {this.state = 'rejected'}this.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())}try {executor(resolve, reject)} catch(err) {reject(err)}}then(onFulfilled, onRejected) {// onFulfilled 如果不是函数,忽略 onFulfilled, 直接返回 valueonFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val// onRejected 如果不是函数,忽略 onRejected, 让它等于一个函数,并且在函数内继续将 err 向下抛出onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err}let promise2 = new Promise((resolve, reject) => {if (this.state === 'fulfilled') {// 异步setTimeout(() => {try {let x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject)} catch(err) {reject(err)}}, 0)}if (this.state === 'rejected') {// 异步setTimeout(() => {try {let x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject)} catch(err) {reject(err)}}, 0)}if (this.state === 'pending') {this.onResolvedCallbacks.push(() => {// 异步setTimeout(() => {try {let x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject)} catch(err) {reject(err)}}, 0)})this.onRejectedCallbacks.push(() => {// 异步setTimeout(() => {try {let x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject)} catch(err) {reject(err)}}, 0)})}})return promise2}
}
添加 catch 方法
class myPromise {constructor(executor) {...}then(onFulfilled, onRejected) {...}// Promise 中的 catch 指代的就是 then 没有成功回调的一个别名而已catch(errCallback) {return this.then(null, errCallback);}
}
添加 finally 方法
// 无论如何都会执行,把上一个 then 的结果向下传递
// 如果 finally 中返回了一个 Promise 会等待这个 Promise 执行完成后继续执行
myPromise.prototype.finally = function(callback) {return this.then(val => {return Promise.resolve(callback()).then(() => val);}, (err) => {return Promise.resolve(callback()).then(() => { throw err; });});
};
添加 resolve、reject、race、all 等方法
// Promise.resolve 会等待里面的 Promise 执行成功
Promise.resolve = val => {return new Promise((resolve) => {resolve(val);});
};// Promise.reject 不会等待参数中的 Promise 执行完毕
Promise.reject = () => {return new Promise((_, reject) => {reject(val);});
};// all 方法表示等待所有的 Promise 全部成功后才会执行回调
// 如果有一个 Promise 失败则 Promise 就失败了
Promise.all = promises => {return new Promise((resolve, reject) => {// 存放结果const res = [];// 计数,当count 等于 length的时候就resolvelet count = 0;const resolveRes = (index, data) => {// 将执行结果缓存在res中res[index] = data;// 所有子项执行完毕之后,执行resolve 抛出所有的执行结果if (++count === promises.length) {resolve(res);}};// 循环遍历每一个参数的每一项for(let i = 0; i < promises.length; i++) {const current = promises[i];// 如果当前项是Promise,则返回 then 的结果if (isPromise(current)) {current.then((data) => {resolveRes(i, data);}, (err) => {reject(err);});} else {resolveRes(i, current);}}});
}// race谁是第一个完成的,就用他的结果
// 如果失败这个 Promise 就失败,如果第一个是成功就是成功
Promise.race = (promises) => {return new Promise((resolve, reject) => {for(let i = 0; i < promises.length; i++) {let current = promises[i];// 如果是一个 promise 继续执行 thenif (isPromise(current)) {current.then(resolve, reject);} else {// 是普通值则直接 resolve 返回,并终止循环resolve(current);break;}}});
}
如何验证我们的 Promise 是否正确?
- 先在后面加上下述代码
// 目前是通过他测试 他会测试一个对象 // 语法糖 Promise.defer = Promise.deferred = function () {let dfd = {}dfd.promise = new Promise((resolve,reject)=>{dfd.resolve = resolve;dfd.reject = reject;});return dfd; } module.exports = Promise; //npm install promises-aplus-tests 用来测试自己的 promise 符不符合 promises A+ 规范
- npm 有一个 promises-aplus-tests 插件
// Windows 全局安装 npm i promises-aplus-tests -g // Mac 全局安装 sudo npm i promises-aplus-tests -g
- 命令行 promises-aplus-tests [js文件名],即可验证
注意⚠️:本文 Promise 已满足基本使用,但还是存在一些问题待改进。。。
参考
史上最最最详细的手写Promise教程
Promise 实现原理
相关文章:
Promise 详解(原理篇)
目录 什么是 Promise 实现一个 Promise Promise 的声明 解决基本状态 添加 then 方法 解决异步实现 解决链式调用 完成 resolvePromise 函数 解决其他问题 添加 catch 方法 添加 finally 方法 添加 resolve、reject、race、all 等方法 如何验证我们的 Promise 是否…...
动态内存经典笔试题分析
目录 1.题目一 2.题目二 3.题目三 4.题目四 1.题目一 #include<stdlib.h> #include<stdio.h> #include<string.h> void GetMemory(char* p) {p (char*)malloc(100); } void Test(void) {char* str NULL;GetMemory(str);strcpy(str, "hello world…...
JS设计模式(一)单例模式
注释很详细,直接上代码 本文建立在已有JS面向对象基础的前提下,若无,请移步以下博客先行了解 JS面向对象(一)类与对象写法 特点和用途: 全局访问点:通过单例模式可以在整个应用程序中访问同一个…...
uniapp动态计算并设置元素高度
<template><view><scroll-view id"sv-box" :scroll-y"true" :style"{height:navHeightpx}"></scroll-view><view id"btn-box"><button>取消</button><button>确认</button><…...
直播架构如何设计核心节点和边缘节点
在直播架构中,核心节点和边缘节点的分工及主要服务是确保直播服务稳定、高效和可扩展的关键。以下是对这些节点的详细描述: 核心节点 核心节点通常位于数据中心,负责处理直播的主要逻辑和数据处理。其主要服务包括: 直播管理后…...
自动驾驶-预测概览
通过生成一条路径来预测一个物体的行为,在每一个时间段内,为每一辆汽车重新计算预测他们新生成的路径,这些预测路径为规划阶段做出决策提供了必要信息 预测路径有实时性的要求,预测模块能够学习新的行为。我们可以使用多源的数据…...
基于PSO算法优化PID参数的一些问题
目录 前言 Q1:惯性权重ω如何设置比较好?学习因子C1和C2如何设置? Q2:迭代速度边界设定一定能够遍历(/覆盖)整个PID参数二维空间范围吗?还是说需要与迭代次数相关?迭代次数越高&a…...
什么是决策树?
1. 什么是决策树? 决策树(Decision Tree)是一种常用的机器学习算法,用于解决分类和回归问题。它通过构建树结构来表示决策过程,分支节点表示特征选择,叶节点表示类别或回归值。 2. 决策树的组成部分 决策…...
ASP 快速参考
ASP 快速参考 概述 ASP(Active Server Pages)是一种由微软开发的服务器端脚本环境,用于动态网页设计和开发。它允许开发者创建和运行动态交互性网页,如访问数据库、发送电子邮件等。ASP页面通常以.asp为文件扩展名,并…...
(二)原生js案例之数码时钟计时
原生js实现的数字时间上下切换显示时间的效果,有参考相关设计,思路比较难,代码其实很简单 效果 代码实现 必要的样式 <style>* {padding: 0;margin: 0;}.content{/* text-align: center; */display: flex;align-items: center;justif…...
[CSS] 浮动布局的深入理解与应用
文章目录 浮动的简介元素浮动后的特点解决浮动产生的影响浮动后的影响解决浮动产生的影响 浮动相关属性实际应用示例示例1:图片与文字环绕示例2:多列布局示例3:响应式布局 总结 浮动布局是CSS中一种非常强大的布局方式,最初设计用…...
Linux云计算 |【第一阶段】ENGINEER-DAY2
主要内容: 磁盘空间管理fdisk、parted工具、开机自动挂载、文件系统、交换空间 KVM虚拟化 实操前骤: 1)添加一块硬盘(磁盘),需要关机才能进行操作,点击左下角【添加硬件】 2)选择2…...
9.11和9.9哪个大?
没问题 文心一言 通义千问...
学懂C语言(十二):C语言中的二进制原理及应用
目录 1. 二进制原理 1.1 什么是二进制? 1.2 如何在C语言中表示二进制? 2. 二进制的表示 2.1 二进制和其他进制的转换 2.2 C语言中的二进制表示 3. 二进制运算 3.1 位运算符 3.2 计算过程示例 4. 应用示例 4.1 使用位运算实现开关 5. 总结 C语…...
科研绘图系列:R语言雨云图(Raincloud plot)
介绍 雨云图(Raincloud plot)是一种数据可视化工具,它结合了多种数据展示方式,旨在提供对数据集的全面了解。雨云图通常包括以下几个部分: 密度图(Density plot):表示数据的分布情况,密度图的曲线可以展示数据在不同数值区间的密度。箱线图(Box plot):显示数据的中…...
优化教学流程和架构:构建高效学习环境的关键步骤
在教育领域,设计和优化教学流程和架构是提高学习效果和学生参与度的关键。本文将探讨如何通过合理的教学流程和有效的架构来构建一个高效的学习环境。 ### 1. 理解教学流程和架构的重要性 教学流程指的是教学活动的组织和顺序,而教学架构则是指支持教学…...
js | this 指向问题
https://juejin.cn/post/6844904083707396109 任何函数运行的时候,都会创建一个context对象,context对象有一个this对象,在运行的时候决定。任何函数都对应一个reference类结构体(具体叫啥有点忘了),简单就…...
《昇思 25 天学习打卡营第 15 天 | 基于MindNLP+MusicGen生成自己的个性化音乐 》
《昇思 25 天学习打卡营第 15 天 | 基于MindNLPMusicGen生成自己的个性化音乐 》 活动地址:https://xihe.mindspore.cn/events/mindspore-training-camp 签名:Sam9029 MusicGen概述 MusicGen是由Meta AI的Jade Copet等人提出的一种基于单个语言模型&…...
Gitee 使用教程1-SSH 公钥设置
一、生成 SSH 公钥 1、打开终端(Windows PowerShell 或 Git Bash),通过命令 ssh-keygen 生成 SSH Key: ssh-keygen -t ed25519 -C "Gitee SSH Key" 随后摁三次回车键(Enter) 2、查看生成的 SSH…...
理解Cookie、Session和Token
在现代Web开发中,用户身份认证和会话管理是至关重要的部分。理解Cookie、Session和Token的区别和应用场景,有助于我们设计出更加安全和高效的Web应用。本文将详细探讨这三者的工作原理、优缺点以及使用场景。 1. Cookie 1.1 什么是Cookie? …...
概率论原理精解【1】
文章目录 测度概述集类笛卡尔积定义例子 多集合的笛卡尔积定义计算方法注意事项 有限笛卡尔积的性质1. 定义2. 性质2.1 基数性质2.2 空集性质2.3 不满足交换律2.4 不满足结合律2.5 对并和交运算满足分配律 3. 示例4. 结论 参考链接 测度 概述 所谓测度,通俗的讲就…...
数据结构(二叉树-1)
文章目录 一、树 1.1 树的概念与结构 1.2 树的相关术语 1.3 树的表示 二、二叉树 2.1 二叉树的概念与结构 2.2特殊的二叉树 满二叉树 完全二叉树 2.3 二叉树的存储结构 三、实现顺序结构二叉树 3.1 堆的概念与结构 3.2 堆的实现 Heap.h Heap.c 默认初始化堆 堆的销毁 堆的插入 …...
巴黎奥运会倒计时 一个非常不错的倒计时提醒
巴黎奥运会还有几天就要开幕了,大家应该到处都可以看到巴黎奥运会的倒计时,不管是电视上,还是网络里,一搜索奥运会,就会看到。倒计时其实是一个我们在生活中很常用的一个方法,用来做事情的提醒,…...
【Python】使用库 -- 详解
库就是别人已经写好了的代码,可以让我们直接拿来用。 一个编程语言能不能流行起来,一方面取决于语法是否简单方便容易学习,一方面取决于生态是否完备。所谓的 “生态” 指的就是语言是否有足够丰富的库,来应对各种各样的场景。在…...
Web3D:WebGL为什么在渲染性能上输给了WebGPU。
WebGL已经成为了web3D的标配,市面上有N多基于webGL的3D引擎,WebGPU作为挑战者,在渲染性能上确实改过webGL一头,由于起步较晚,想通过这个优势加持,赶上并超越webGL仍需时日。 贝格前端工场为大家分享一下这…...
SpringBoot面试高频总结01
1. 什么是SpringBoot? SpringBoot是一个基于Spring框架的快速开发框架,它采用约定大于配置,自动装配的方式,可以快速地创建独立的,生产级别的,基于Spring的应用程序。 相比于传统的Spring框架,S…...
Linux 工作队列(Workqueue):概念与实现
目录 一、工作队列的概念1.1 什么是工作队列1.2 为什么使用工作队列 二、工作队列的实现2.1 定义和初始化工作队列2.2 工作队列API 三、工作队列的应用3.1 延迟执行任务3.2 处理复杂的中断任务 四、工作队列的类型4.1 普通工作队列4.2 高优先级工作队列 五、总结 在Linux内核中…...
前端页面是如何禁止被查看源码、被下载,被爬取,以及破解方法
文章目录 1.了解禁止查看,爬取原理1.1.JS代码,屏蔽屏蔽键盘和鼠标右键1.2.查看源码时,通过JS控制浏览器窗口变化2.百度文库是如何防止抓包2.1.HTPPS2.2. 动态加载为什么看不到?如何查看动态加载的内容?3.禁止复制,如果解决3.1.禁止复制原理3.2.如何破解1.了解禁止查看,爬…...
51单片机嵌入式开发:14、STC89C52RC 之HX1838红外解码NEC+数码管+串口打印+LED显示
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 STC89C52RC 之HX1838红外解码NEC数码管串口打印LED显示 STC89C52RC 之HX1838红外解码NEC数码管串口打印LED显示1 概述2 硬件电路2.1 遥控器2.2 红外接收器电路2.3 STC89C52单…...
在不同环境中,Java应用程序和MySQL等是如何与Docker进行交互和操作的?
1. 本地开发环境 在本地开发环境中,可以使用Docker Compose来管理和运行Java应用程序容器和MySQL容器。通常,会创建一个docker-compose.yml文件,定义需要的服务及其配置。 以下是一个示例docker-compose.yml文件: version: 3 services:app…...
网上做衣服的网站有哪些/seo博客网站
要解决JSP乱码,首先就要了解JSP乱码的原因1.架设服务器安装MYSQL时的会让你选择一种编码,如果这种编码与你的网页不一致,可能就会造成JSP页面乱码2.在PHPMYADMIN或mysql-front等系统 创建数据库时会让你选择一种编码,如果这种编码与你的网页不一致,也有可能造成JSP页面乱码3.创…...
@wordpress/百度提交入口网址是什么
在XML中需要插入自己的字符串,但是发现&<>"这些字符无法替换掉,使用正常的Replace没有效果,网上也没有找到合适的。并且由于是控制台程序,无法引用NET类,经过查询MSDN得到些启发,写下这个转…...
动态网站系统是什么/游戏交易平台
文章目录商品服务-分类管理查出所有分类以及子分类后端编写前端展示服务注册配置网关503问题跨域跨域流程解决跨域服务注册配置网关删除数据后端接口逻辑删除测试前端请求删除数据新增分类修改分类拖拽效果批量删除谷粒商城_01_环境搭建 谷粒商城_02_Nacos、网关 谷粒商城_03_前…...
陕西省人民政府采购网/曲靖seo
本文同步发布于 个人博客 前言 上周周赛因为忘记起床导致没打TAT 本次周赛战绩: rk5,总完成时间20min,还有奖品,好耶! A 2129.将标题首字母大写 题意 给出一个包含若干个单词的句子,把所有字母变为小写字母&#…...
wordpress分类排序号/全自动推广软件
被调合约(通过call回调)支持接收以太币的案例: 被调合约(通过call回调)支持接收以太币的案例:pragma solidity >0.4.0 <0.6.0;contract Test001 {// 这个合约会保留所有发送给它的以太币,没有办法返还。// 必须实现Fallback回退函数,才能支持cal…...
成品网站建设价格/网站不收录怎么解决
Nginx作为当前最流行的负载均衡和反向代理服务器,它运行在linux平台,一般的.net网站,为了实现分流与负载,需要在多个应用服务器的IIS上部署,通过一些工具实现代码的同步,然后再nginx上去配置它们. 有了docker,你可以在多个linux上花个1秒钟去run它即可,不用在iis上部署了,对于d…...