【手写 Promise 源码】第四篇 - 翻译并理解 Promise A+ 规范

news2024/11/28 1:43:59

一,前言

上一篇,根据对 Promise 的分析和了解,实现了一个简版 Promise,主要涉及以下内容:

  • Promise 的实现思路;
  • Promise A+ 规范(简版);
  • Promise 简版实现和功能测试;

本篇,翻译并理解 Promise A+ 规范;

备注:虽然 Promise 的翻译网上很多,还是决定按自己的理解翻译一遍;


二,1)Promise A+ 简介

官网:https://promisesaplus.com/

原文

An open standard for sound, interoperable JavaScript promises—by implementers, for implementers.

A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise’s eventual value or the reason why the promise cannot be fulfilled.

This specification details the behavior of the then method, providing an interoperable base which all Promises/A+ conformant promise implementations can be depended on to provide. As such, the specification should be considered very stable. Although the Promises/A+ organization may occasionally revise this specification with minor backward-compatible changes to address newly-discovered corner cases, we will integrate large or backward-incompatible changes only after careful consideration, discussion, and testing.

Historically, Promises/A+ clarifies the behavioral clauses of the earlier Promises/A proposal, extending it to cover de facto behaviors and omitting parts that are underspecified or problematic.

Finally, the core Promises/A+ specification does not deal with how to create, fulfill, or reject promises, choosing instead to focus on providing an interoperable then method. Future work in companion specifications may touch on these subjects.

翻译

  • 一个开放、健全且通用的 JavaScript Promise 标准。由开发者制定,供开发者参考。
  • Promise 表示一个异步操作的最终结果,与 Promise 进行交互的主要方式是 then 方法,该方法注册了两个回调函数,用于接收 promise 的最终值或该 promise 不能完成的原因。
  • 该规范详细说明了then方法的行为,所有遵循该 Promises/A+ 规范实现的 promise 都能够以本标准作为参照基础来实现 then 方法。因而本规范是十分稳定的。尽管 Promises/A+ 组织可能偶尔会修改本规范,会进行一些向下兼容的更改以解决新发现的边界情况,但只有在仔细考虑、讨论和测试之后,我们才会进行大规模的或不兼容的更改。
  • 从历史上看,Promises/A+规范使早起的Promises/A提案中的行为条款更加清晰,并扩展了原有规范约定俗成的行为,删减了原规范的一些特例情况和有问题的部分。
  • 最后,核心的Promises/A+规范不涉及如何创建、实现或拒绝 promise,而是专注于提供一个通用的 then 方法。未来在配套规范中的工作中可能涉及这些主题。

三,2)Terminology(术语)

原文

1.1 “promise” is an object or function with a then method whose behavior conforms to this specification.

1.2 “thenable” is an object or function that defines a then method.

1.3 “value” is any legal JavaScript value (including undefined, a thenable, or a promise).

1.4 “exception” is a value that is thrown using the throw statement.

1.5 “reason” is a value that indicates why a promise was rejected.

翻译

1.1 Promise
promise 是一个拥有 then 方法的对象或函数,其行为符合本规范;

1.2 thenable
是一个定义了(拥有) then 方法的对象或函数;

1.3 值(value)
是任何合法的 JavaScript 值(包括 undefined , thenable 和 promise);

1.4 异常(exception)
是使用 throw 语句抛出的一个值。

1.5 原因(reason)
是一个值,表示 promise 的拒绝原因。 

四,3)Requirements(要求)

3.1,Promise States(Promise 状态)

A promise must be in one of three states: pending, fulfilled, or rejected.

2.1.1,When pending, a promise:
        2.1.1.1,may transition to either the fulfilled or rejected state.
2.1.2 When fulfilled, a promise:
        2.1.2.1must not transition to any other state.
        2.1.2.2must have a value, which must not change.
2.1.3 When rejected, a promise:
        2.1.3.1 must not transition to any other state.
        2.1.3.2 must have a reason, which must not change.
Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.
  • 一个 Promise 的当前状态必须为以下三种状态之一:
    • 等待态(Pending)
    • 成功态(Fulfilled)
    • 失败态(Rejected)
  • 2.1.1,当一个 promise 处于等待态时:
    • 2.1.1.1,可以转变为成功态或失败态
  • 2.1.2 当一个 promise 处于成功态时:
    • 2.1.2.1,不能转变为其他任何状态
    • 2.1.2.2,必须有一个值,且不可被更改
  • 2.1.3 当一个 promise 处于拒绝态时:
    • 2.1.3.1,不能转变为其他任何状态
    • 2.1.3.2,必须有一个原因,且不可被更改

这里的“不可变”,指的是恒等(即可用 === 判断相等),但并不意味着深层次的不可变
(指当前的引用空间不能被更改)

3.2,The then Method(then 方法)

A promise must provide a then method to access its current or eventual value or reason.
A promise’s then method accepts two arguments:
promise.then(onFulfilled, onRejected)

一个 promise 必须提供一个 then 方法以访问其当前值、最终值和失败原因。
promise 的 then 方法接受两个参数:
	promise.then(onFulfilled, onRejected)

2.2.1,Both onFulfilled and onRejected are optional arguments:
	2.2.1.1,If onFulfilled is not a function, it must be ignored.
	2.2.1.2,If onRejected is not a function, it must be ignored.
  
2.2.1,onFulfilled and onRejected 都是可选参数:
	2.2.1.1,如果 onFulfilled 不是一个 function, 那么 onFulfilled 函数必须被忽略.
	2.2.1.2,如果 onRejected 不是一个 function, 那么 onRejected 函数必须被忽略.
  
2.2.2,If onFulfilled is a function:
	2.2.2.1,it must be called after promise is fulfilled, with promise’s value as its first argument.
	2.2.2.2,it must not be called before promise is fulfilled;
	2.2.2.3,it must not be called more than once;
  
2.2.2,如果 onFulfilled 是一个 function:
	2.2.2.1,在 promise 状态为成功态时,onFulfilled必须被调用,promise 的值作为其第一个参数;
	2.2.2.2,在 promise 状态为成功态前,onFulfilled不可被调用;
	2.2.2.3,onFulfilled 不能被调用多次;
  
2.2.3,如果 onRejected 是一个 function:
	2.2.3.1,在 promise 状态为失败态时,onRejected 必须被调用,promise 的原因作为其第一个参数;
	2.2.3.2,在 promise 状态为失败态前,onRejected 不可被调用;
	2.2.3.3,onRejected 不能被调用多次;
  
2.2.4,onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
2.2.4,onFulfilled 或 onRejected 只允许在 execution context 栈仅包含平台代码时运行. [3.1].

2.2.5,onFulfilled and onRejected must be called as functions (i.e. with no this value). [3.2]
2.2.5,onFulfilled 和 onRejected 必须被当做函数调用 (ie 中的 this 为undefined). [3.2]

2.2.6,then may be called multiple times on the same promise.
	2.2.6.1,If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
	2.2.6.2,If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.
  
2.2.6,同一个 promise,then 方法可被多次调用
	2.2.6.1,当 promise 为成功态时,所有 onFulfilled 回调函数都必须按照其注册顺序被执行
	2.2.6.2,当 promise 为失败态时,所有 onRejected 回调函数都必须按照其注册顺序被执行
  
2.2.7,then must return a promise [3.3].
 promise2 = promise1.then(onFulfilled, onRejected);
	2.2.7.1,If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
	2.2.7.2,If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
	2.2.7.3,If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
	2.2.7.4,If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
  
2.2.7,then方法必须返回一个 promise 对象 [3.3].
 promise2 = promise1.then(onFulfilled, onRejected);
	2.2.7.1,如果 onFulfilled 或 onRejected 返回值x,则执行 Promise 解析流程[[Resolve]](promise2, x).
	2.2.7.2,如果 onFulfilled 或 onRejected 抛出异常e,则 promise2 为失败态,原因是 e。
	2.2.7.3,如果 onFulfilled 不是一个函数且 promise1 是成功态,则 promise2 为成功态,且值与 promise1 相同.
	2.2.7.4,如果 onRejected 不是一个函数且 promise1 是失败态, 则 promise2 为失败态,且原因与 promise1 相同.

3.3,The Promise Resolution Procedure(Promise的解析过程)

The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.
Promise的解析过程,是以一个 promise 和 一个值 做为参数的抽象过程,可表示为[[Resolve]](promise, x).
如果 x 是一个 thenable,它试图使 promise 采用 x 状态,假设 x 的行为至少有点像 promise .否则,使用 x 的值执行promise.

This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.

To run [[Resolve]](promise, x), perform the following steps:
要运行[[Resolve]](promise,x),请执行以下步骤:

2.3.1,If promise and x refer to the same object, reject promise with a TypeError as the reason.
2.3.1,如果promise 和 x 指向相同的值, 使用 TypeError做为原因将promise拒绝。

2.3.2,If x is a promise, adopt its state [3.4]:
	2.3.2.1,If x is pending, promise must remain pending until x is fulfilled or rejected.
	2.3.2.2,If/when x is fulfilled, fulfill promise with the same value.
	2.3.2.3,If/when x is rejected, reject promise with the same reason.
2.3.2,如果 x 是一个 promise, 采用它的状态 [3.4]:
	2.3.2.1,如果 x 是 pending 状态,promise必须保持pending,直至 x 转变为 fulfilled 或 rejected.
	2.3.2.2,如果 x 是 fulfilled 状态,fulfill promise 使用 x 值.
	2.3.2.3,如果 x 是 rejected 状态, reject promise 使用 x 值作为 reason.

2.3.3,Otherwise, if x is an object or function,
	2.3.3.1,Let then be x.then. [3.5]
	2.3.3.2,If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
	2.3.3.3,If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:
		2.3.3.3.1,If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
		2.3.3.3.2,If/when rejectPromise is called with a reason r, reject promise with r.
		2.3.3.3.3,If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
		2.3.3.3.4,If calling then throws an exception e,
			2.3.3.3.4.1,If resolvePromise or rejectPromise have been called, ignore it.
			2.3.3.3.4.2,Otherwise, reject promise with e as the reason.
	2.3.3.4,If then is not a function, fulfill promise with x.
2.3.3,如果 x 是一个对象或一个函数,
2.3.3.1,将 then 赋值为 x.then. [3.5]
	2.3.3.2,如果取 x.then 的值时抛出了异常,使用此异常做为promise reject 的 reason 值.
	2.3.3.3,如果 then 是一个函数, 以 x 作为this 调用 这个 then 函数, 第一个参数为 resolvePromise,第二个参数是rejectPromise:
		2.3.3.3.1,如果 resolvePromise 以 y 值被调用, 执行 [[Resolve]](promise, y).
		2.3.3.3.2,如果 rejectPromise 以 r 为 reason 被调用, 则以 r 为 reason 将 promise 拒绝.
		2.3.3.3.3,如果 resolvePromise 和 rejectPromise 都被调用了,或以相同的参数多次被调用,则只第一次调用生效,后面的调用将被忽略.
		2.3.3.3.4,如果调用 then 时抛出了异常:
			2.3.3.3.4.1,如果 resolvePromise 或 rejectPromise 已经被调用了,则忽略它.
			2.3.3.3.4.2,否则, 则 reject promise 以 e 作为 reason.
      
2.3.4,If x is not an object or function, fulfill promise with x.
2.3.4,如果 x 不是一个对象或函数,则 fulfill promise 以 x 为值 。

If a promise is resolved with a thenable that participates in a circular thenable chain, such that the recursive nature of [[Resolve]](promise, thenable) eventually causes [[Resolve]](promise, thenable) to be called again, following the above algorithm will lead to infinite recursion. Implementations are encouraged, but not required, to detect such recursion and reject promise with an informative TypeError as the reason. [3.6]


Promise 解决过程 是一个抽象的操作,其需输入一个 promise 和一个值,我们表示为 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。

这种 thenable 的特性使得 Promise 的实现更具有通用性:只要其暴露出一个遵循 Promise/A+ 协议的 then 方法即可;这同时也使遵循 Promise/A+ 规范的实现可以与那些不太规范但可用的实现能良好共存。

运行 [[Resolve]](promise, x) 需遵循以下步骤:

2.3.1 x 与 promise 相等
如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise

2.3.2 x 为 Promise
如果 x 为 Promise ,则使 promise 接受 x 的状态:注4

如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
如果 x 处于执行态,用相同的值执行 promise
如果 x 处于拒绝态,用相同的据因拒绝 promise
2.3.3 x 为对象或函数
如果 x 为对象或者函数:

把 x.then 赋值给 then注5
如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
如果then是函数,将x作为函数的作用域this调用之。传递两个回调函数作为参数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise:
如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
如果调用then方法抛出了异常e:
如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
否则以 e 为据因拒绝 promise
如果 then 不是函数,以 x 为参数执行 promise
2.3.4 x 不为对象或函数
如果 x 不为对象或者函数,以 x 为参数执行 promise

如果一个 promise 被一个循环的 thenable 链中的对象解决,而 [[Resolve]](promise, thenable) 的递归性质又使得其被再次调用,根据上述的算法将会陷入无限递归之中。算法虽不强制要求,但也鼓励施者检测这样的递归是否存在,若检测到存在则以一个可识别的 TypeError 为据因来拒绝 promise。注6

五,4)Notes(注释)

3.1,Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

3.2,That is, in strict mode this will be undefined inside of them; in sloppy mode, it will be the global object.

3.3,Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1 and under what conditions.

3.4,Generally, it will only be known that x is a true promise if it comes from the current implementation. This clause allows the use of implementation-specific means to adopt the state of known-conformant promises.

3.5,This procedure of first storing a reference to x.then, then testing that reference, and then calling that reference, avoids multiple accesses to the x.then property. Such precautions are important for ensuring consistency in the face of an accessor property, whose value could change between retrievals.

3.6,Implementations should not set arbitrary limits on the depth of thenable chains, and assume that beyond that arbitrary limit the recursion will be infinite. Only true cycles should lead to a TypeError; if an infinite chain of distinct thenables is encountered, recursing forever is the correct behavior.


3.1 注1
这里的平台代码指的是引擎、环境以及 promise 的实施代码。实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。这个事件队列可以采用“宏任务(macro-task)”机制或者“微任务(micro-task)”机制来实现。由于 promise 的实施代码本身就是平台代码(译者注: 即都是 JavaScript),故代码自身在处理在处理程序时可能已经包含一个任务调度队列或『跳板』。

译者注: 这里提及了 macrotask 和 microtask 两个概念,这表示异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

两个类别的具体分类如下:

macro-task: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering

micro-task: process.nextTick, Promises(这里指浏览器实现的原生 Promise), Object.observe, MutationObserver

详见 stackoverflow 解答 或 这篇博客

3.2 注2
也就是说在 严格模式(strict) 中,函数 this 的值为 undefined ;在非严格模式中其为全局对象。

3.3 注3
代码实现在满足所有要求的情况下可以允许 promise2 === promise1 。每个实现都要文档说明其是否允许以及在何种条件下允许 promise2 === promise1 。

3.4 注4
总体来说,如果 x 符合当前实现,我们才认为它是真正的 promise 。这一规则允许那些特例实现接受符合已知要求的 Promises 状态。

3.5 注5
这步我们先是存储了一个指向 x.then 的引用,然后测试并调用该引用,以避免多次访问 x.then 属性。这种预防措施确保了该属性的一致性,因为其值可能在检索调用时被改变。

3.6 注6
实现不应该对 thenable 链的深度设限,并假定超出本限制的递归就是无限循环。只有真正的循环递归才应能导致 TypeError 异常;如果一条无限长的链上 thenable 均不相同,那么递归下去永远是正确的行为。
To the extent possible under law, the Promises/A+ organization has waived all copyright and related or neighboring rights to Promises/A+ Promise Specification. This work is published from: United States.

在法律允许的范围内,Promises/A+ 组织已放弃 Promises/A+ Promise规范 的所有版权和相关或相邻权利。
这项工作发表于:美国。

六,结尾

本篇,翻译并理解了整个 Promise A+ 规范;

接下来,将基于 Promise A+ 规范,继续对简版 Promise 代码功能进行完善;

下一篇,Promise 链式调用的实现;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/180394.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

KVM虚拟化之小型虚拟机kvmtool的使用记录

根据 kvmtool github仓库文档的描述,类似于QEMU,kvmtool是一个承载KVM Guest OS的 host os用户态虚拟机,作为一个纯的完全虚拟化的工具,它不需要修改guest os即可运行, 不过,由于KVM基于CPU的硬件虚拟化支持&#xff0…

读《哲学的故事》

文章目录读《哲学的故事》🚩 遇见🌻 简述🌾 部分摘抄读《哲学的故事》 一本书读过后,我有种脑子里又被塞进了很多新东西的感觉,也有种想要自我抒发、宣泄的欲望。可真到要说的时候,又好像无话可说。总归勉…

Java转换流(InputStreamReader/OutputStreamWriter)

文章目录概述为什么会有转换流?InputStreamReaderOutputStreamWriter概述 转换流是字节流到字符流的桥梁,在转换的过程中,可以指定编码。转换流也是一种处理流,它提供了字节流和字符流之间的转换。 转换流的两个类 InputStreamR…

1.设计模式的前奏

哪些维度评判代码质量的好坏? 常用的评价标准 可维护性(maintainability):维护代码的成本可读性(readability)可扩展性(extensibility):码应对未来需求变化的能力灵活性&#xff0…

【keepass】密码管理软件-推荐插件和相关工具合集-keepass工作流分析(自动填充、美化界面、快速添加记录、安全增强、软件和数据库维护类)

Keepass有很多已经开源的插件,生态良好,在官网有专门的插件推荐区。安装插件的方法很简单,直接把下载好的插件文件放在plugins文件夹内,重启软件即可。下面我以几大功能推荐一些keepass插件或搭配使用的浏览器扩展,以求…

Coolify系列-手把手教学解决局域网局域网中的其他主机访问虚拟机以及docker服务

背景 我在windows电脑安装了一个VM,使用VM开启了Linux服务器,运行docker,下载服务镜像,然后运行服务,然后遇到了主机无法访问服务的问题。 问题排查 STEP1:首先要开启防火墙端口,这个我的Coolify系列其他文章有详细…

【c++】设置控制台窗口字体颜色和背景色(system和SetConsoleTextAttribute函数 )(内含超好玩的c++游戏链接)

目录 游戏推荐 研究初步 SetConsoleTextAttribute函数 原型 参数 举个栗子 最后 题外话 一篇游戏笔记。。。 游戏推荐 最近,在玩(完)一个c的控制台游戏。 啊,真的非常好玩。虽然是一个文字游戏,但有很多隐…

分享137个ASP源码,总有一款适合您

ASP源码 分享137个ASP源码,总有一款适合您 下面是文件的名字,我放了一些图片,文章里不是所有的图主要是放不下..., 137个ASP源码下载链接:https://pan.baidu.com/s/13nF0yADJhSBonIFUIoymPQ?pwdmsl8 提取码&#x…

【C++】位图、布隆过滤器概念与模拟实现

目录 一、位图 1.1 位图的概念 1.2 位图的使用 1.3 位图的实现 1.4 位图的应用 二、布隆过滤器 2.1 布隆过滤器 2.2 布隆过滤器的实现 2.3 布隆过滤器练习题 一、位图 1.1 位图的概念 所谓位图,就是用每一位来存放某种状态,适用于海量数据&am…

监控Python 内存使用情况和代码执行时间

我的代码的哪些部分运行时间最长、内存最多?我怎样才能找到需要改进的地方?” 在开发过程中,我很确定我们大多数人都会想知道这一点,而且通常情况下存在开发空间。在本文中总结了一些方法来监控 Python 代码的时间和内存使用情况…

【24】C语言 | 调试技巧

目录 1、调试概念: 2、Debug和Release的介绍 3、windows中的快捷键 4、案例一:求1! 2!3!...n! 5、案例二:下面的代码输出什么? 6、案例三:实现一个strcopy的函数 …

零入门容器云网络实战-3->Underlay网络与Overlay网络总结

本篇文章主要用于收集、整理、总结关于Underlay网络以及overlay网络相关知识点。 1、underlay网络介绍? 1.1、什么是underlay网络? Underlay网络就是: 传统IT基础设施网络,由交换机和路由器等设备组成,借助以太网协议…

3分钟搭建起聊天机器人需要的NoneBot2环境

创建nonebot2运行环境 官网上说这里的Python版本要高于3.8.0,还会有其他的依赖。 所以这里推荐大家使用虚拟环境,Poetry、venv、Conda,我这里用的是conda环境(不同的项目依赖可能有所不同,所以才创建虚拟环境&#xf…

[羊城杯 2020]EasySer

目录 信息搜集 代码审计 参数扫描 信息搜集 先扫下目录 .htaccess&#xff1b;robots.txt&#xff1b;flag.php&#xff1b;index.php 在robots.txt下看到了/star1.php 进入star1.php发现出现ser.php <!-- 小胖说用个不安全的协议从我家才能进ser.php呢&#xff01; !--…

蓝桥杯刷题015——最少刷题数(二分法+前缀和)

问题描述 小蓝老师教的编程课有 N 名学生, 编号依次是 1…N 。第 i 号学生这学期刷题的数量是 Ai​ 。 对于每一名学生, 请你计算他至少还要再刷多少道题, 才能使得全班刷题比他多的学生数不超过刷题比他少的学生数。 输入格式 第一行包含一个正整数 N 。 第二行包含 N 个整数:…

学成在线项目开发技巧整理---第一部分

学成在线项目开发技巧整理---第一部分1.数据字典2.http-client远程测试插件,可以保存测试数据3.三种跨域解决4.具有多层级数据查询思路5.Mybaits分页插件原理6.根据文件后缀解析出mime-type7.大文件上传8.Spring事务什么时候会失效9.分布式文件系统MinIo10.构建独立文件系统11.…

3.3Sram和Dram

文章目录一、引子二、存储元件1.DRAM芯片&#xff08;1&#xff09;栅极电容1&#xff09;存储2&#xff09;读出&#xff08;2&#xff09;物理特性&#xff08;3&#xff09;DRAM刷新&#xff08;4&#xff09;DRAM地址线复用2.SRAM芯片&#xff08;1&#xff09;双稳态触发器…

爬虫之JS的解析

JS的解析 学习目标&#xff1a; 了解 定位js的方法了解 添加断点观察js的执行过程的方法应用 js2py获取js的方法 1 确定js的位置 对于前面人人网的案例&#xff0c;我们知道了url地址中有部分参数&#xff0c;但是参数是如何生成的呢&#xff1f; 毫无疑问&#xff0c;参数肯…

gin全解

文章目录介绍安装快速开始&#xff08;三种启动方式&#xff09;参数获取querystring参数其他不常用方法表单参数&#xff08;form参数&#xff09;其他不常用方法获取path参数参数绑定文件上传单个文件多个文件请求&#xff08;ctx.Request)响应gin.H{}字符串响应JSON/YAML/TO…

一起自学SLAM算法:8.2 Cartographer算法

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; Gmapping代码实现相对简洁&#xff0c;非常适合初学者入门学习。但是Gmapping属于基于滤波方法的SLAM系统&#xff0c;明显的缺点是无法构建大规模的地图&#xff0c;这一点已经在第7章中讨论过了。而基于优化的…