深入了解Promise机制并使用JS实现一个Promise(一)

news2024/12/23 18:56:20

前言

关于为什么会有Promise以及Promise的一些用法和基本机制可以参考之前的文章JS中的异步与Promise使用整体来说,Promise可以帮助我们很好的解决异步的问题,号称是异步的终极解决方案。在浏览器中Promise是使用C++实现的,今天就使用js来实现一个JS版本的Promise。这样可以更深层次的帮助我们理解Promise

Promise的状态和值

定义

每一个Promise对象都有三种状态: pending 、resolve 和 reject

  • PENDING : 进行中,Promise 对象的初始状态
  • FULFILLED : 已成功
  • REJECTED : 已失败

每一个 Promise 对象只能由 PENDING 状态变成 FULFILLED 或 REJECTED,且状态发生变化以后就能再改变了
一个 Promise 对象状态的变化并不由 Promise 对象本身来决定,而应该是由我们传入的异步任务完成情况来决定的,Promise 提供了resolve, reject两个用来改变状态的方法

先看原生Promise的效果如下:
在这里插入图片描述

实现三个状态以及值的管理

那我们也要先解决我们自己xpromise的三个状态。可以在我们class中建立两个变量分别记录当前xpromise的状态和值代码如下:

// index.html
<script type="module">
  import XPromise from './xpromise.js'
  const xpromise1 = new XPromise((resolve, reject) => {})
  const xpromise2 = new XPromise((resolve, reject) => {
    resolve(2)
  })
  const xpromise3 = new XPromise((resolve, reject) => {
    reject(3)
  })
console.log(xpromise1);
console.log(xpromise2);
console.log(xpromise3);
</script>
// index.html同级目录 xpromise.js文件
class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
  }

}

export default XPromise

执行的效果如下:
在这里插入图片描述
可以看到我们以及有了状态[[PromiseState]]和值[[PromiseResult]]。但我们在index.html中调用了resolve(2)reject(3)的时候应该要修改对应的状态和值。所以在在xpromise.js中的代码修改如下:

class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
  }

}
export default XPromise

这里注意的是,#resolve和#reject方法使用了箭头函数的写法规避了this指向的问题,如果不使用箭头函数,就需要在构造函数中bind一下this。否则在Promise构造函数中this是undefined,最终执行效果如下
在这里插入图片描述
可以看到xpromise中已近发生了状态的改变,并且也已近有了值

then函数

定义

then() 方法返回一个 Promise (en-US)。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。在成功回调函数中接受成功的值,失败情况的回调函数接受失败的值,比如看原生的promise使用then如下:
在这里插入图片描述

很明显,then的功能有下面几点

  1. 接受成功和失败两个回调函数作为参数
  2. 对应的成功失败回调函数接受resolve和reject的值
  3. 返回一个新的promise

下面我们自己也来实现这个效果,很明显,then函数是一个实例方法,也就是原型链上面的方法

实现promise示例执行then函数

先看同步的promise,我们只需要在then 函数中判断当前promise实例的状态,根据不同的状态去执行onResolveonReject方法并传入当前promise的值即可

class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
  }

  // xpromise实例方法
  then = (onResolved, onReject) => {
    const promiseState = this['[[PromiseState]]']
    const promiseResult = this['[[PromiseResult]]']
    if ( promiseState === 'fulfilled') {
      // 当前xpromise为成功状态
      onResolved && onResolved(promiseResult)
    } else if (promiseState === 'rejected') {
      // 当前xpromise为失败状态
      onReject && onReject(promiseResult)
    }
  }
}

export default XPromise

执行效果如下:
在这里插入图片描述
通过上面我们可以发现,之所以同步的xpromise执行是符合预期的,是因为在XPromise的构造函数中,立马就执行了resolve函数,那么对应的promiseResolve实例的状态就会变成fulfilled。但是异步的XPromise的构造函数中,resolve('asyncPromise val')要在1s之后才能执行,所以当代码执行到asyncPromise.then时,对应的asyncPromiseThen实例状态还是pending所以就不会触发onResolvedonReject函数了。也就不会执行then函数中传入的函数参数了。
在这里插入图片描述

实现异步Promise执行then函数功能

基于上述问题,所以我们需要改造一下,将传递给then函数中的两个函数(onResolve / onReject)参数要在resolve函数执行之后才会执行,所以我们进一步将代码进行如下改造:

class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    this.resolveFn = null
    this.rejectFn = null
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
    // 如果有resolveFn则运行并传入成功的值
    this.resolveFn && this.resolveFn(val)
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
    // 如果有rejectFn则运行,并传入失败的值
    this.rejectFn && this.rejectFn(error)
  }

  // xpromise实例方法
  then = (onResolved, onReject) => {
    // 将成功或失败的两个函数保存至当前xpromise实例
    this.resolveFn = onResolved
    this.rejectFn = onReject
  }
}

export default XPromise

对应的执行效果如下:
在这里插入图片描述
我们发现,异步的promise符合预期的在延迟1s之后打印出来了,但是同步的promise却没有打印出来了。

实现同步&异步Promise执行then函数功能

是因为在同步的Promise实例中的执行resolve函数时,此时this.resolveFn还是null,所以就不会执行,而等到执行promiseResolve.then时,也只是将then函数的入参函数保存到this.resolveFn属性中,并没有执行。
所以要解决这个问题,就必须在执行resolev函数时,就已近把then函数传递的函数参数存入this.resolveFn中。而我们知道promise.then中的函数是微任务(现在还没实现是同步任务),但浏览器会先执行同步任务、微任务、宏任务。所以我们可以把resolve函数中的thie.resolveFn()执行时机放在宏任务重,这样就能保证在判断是否要执行this.resolveFn时就一定有该函数(或者this.rejectFn)。再次将代码做如下改造:

class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    this.resolveFn = null
    this.rejectFn = null
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
    // 将执行this.resolveFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      this.resolveFn && this.resolveFn(val)
    }, 0)
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
    // 将执行this.rejectFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      this.rejectFn && this.rejectFn(error)
    }, 0)
  }

  // xpromise实例方法
  then = (onResolved, onReject) => {
    // 将成功或失败的两个函数保存至当前xpromise实例
    this.resolveFn = onResolved
    this.rejectFn = onReject
  }

}

export default XPromise

执行效果如下:
在这里插入图片描述

实现并行调用then函数的功能

基于上面的代码,我们已近可以实现同步/异步Promise函数的问题。但原生的promise是可以多次并行调用的。
在这里插入图片描述
但我们现在的效果如下:
在这里插入图片描述
可以看到,原生promise并行调用的时候每个then函数里面的入参函数会分别执行而且互相独立。但我们resolve之后执行this.resolveFn这个函数,而在then函数之中是一个覆盖的逻辑,所以最后一次传入then函数的入参函数会将之前传入的函数全部覆盖,只会执行一次。所以我们需要将his.resolveFnthis.rejectFn改变为一个函数队列,然后等resolve函数执行后,依次执行队列中的所有注册函数即可。
代码改造如下:

class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    this.resolveFnList = []
    this.rejectFnList = []
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
    // 将执行this.resolveFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      // 依次执行该promise实例下的多个.then对应的resolve方法
      this.resolveFnList.forEach(resolveFnItem => resolveFnItem(val))
    }, 0)
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
    // 将执行this.rejectFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      // 依次执行该promise实例下的多个.then对应的reject方法
      this.rejectFnList.forEach(rejectFnItem => rejectFnItem(error))
    }, 0)
  }

  // xpromise实例方法
  then = (onResolved, onReject) => {
    // 将成功或失败的两个函数保存至当前xpromise实例
    this.resolveFnList.push(onResolved)
    this.rejectFnList .push(onReject)
  }

}

export default XPromise

执行效果如下图所示:
在这里插入图片描述

实现返回新XPromise功能

我们知道在原生promise对象中,调用then函数之后会返回一个新的Promise对象,所以可以实现链式调用。效果如下:
在这里插入图片描述
所以我们再XPromise中的then函数也需要返回一个新的xpromise对象,将代码改造如下:


class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    this.resolveFnList = []
    this.rejectFnList = []
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
    // 将执行this.resolveFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      // 依次执行该promise实例下的多个.then对应的resolve方法
      this.resolveFnList.forEach(resolveFnItem => resolveFnItem(val))
    }, 0)
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
    // 将执行this.rejectFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      // 依次执行该promise实例下的多个.then对应的reject方法
      this.rejectFnList.forEach(rejectFnItem => rejectFnItem(error))
    }, 0)
  }

  // xpromise实例方法
  then = (onResolved, onReject) => {
    // 将成功或失败的两个函数保存至当前xpromise实例
    return new XPromise((resolve, reject) => {
      // 在这里需要把当前这个promise的结果拿到
      // resolveFn是需要push到函数队列中的,接受当前promise实例的值
      const resolveFn = (val) => {
        const result = onResolved && onResolved(val)
        resolve(result)
      }
      this.resolveFnList.push(resolveFn)

      const rejectFn = (error) => {
        onReject && onReject(error)
        reject(error)
      }
      this.rejectFnList.push(rejectFn)
    })
  }
}

export default XPromise

运行效果如下所示:
在这里插入图片描述
这里需要注意的是,.then方法返回的是一个新的xpromise实例而非当前的promise实例

then中返回promise处理

我们知道在原生promise中的返回可以是undefiend、非promise的值,和promise。对应的效果如下:
在这里插入图片描述
而这里写的xpromise中,在then函数体内未对resolveFn函数的执行结果做区分,如果是一个非xpromise的话直接resolve是可以的,但如果本身已近是xpromise的实例的话,需要拿到当前xpromise的结果再resolve
在这里插入图片描述
我们将代码进行如下改造:


class XPromise {
  constructor(handle) {
    // 用来记录当前XPromise的状态 pending | fulfilled | rejected
    this['[[PromiseState]]'] = 'pending'
    // 用来记录当前XPromise的值
    this['[[PromiseResult]]'] = undefined
    this.resolveFnList = []
    this.rejectFnList = []
    // 使用否箭头函数规避this问题, 否则就得这里bind一下
    // handle(this.#resolve.bind(this), this.#reject.bind(this))
    handle(this.#resolve, this.#reject)
  }

  // 对标promise中的resolve
  #resolve = (val) => {
    this['[[PromiseState]]'] = 'fulfilled'
    this['[[PromiseResult]]'] = val
    // 将执行this.resolveFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      // 依次执行该promise实例下的多个.then对应的resolve方法
      this.resolveFnList.forEach(resolveFnItem => resolveFnItem(val))
    }, 0)
  }

  // 对标promise中的reject
  #reject = (error) => {
    this['[[PromiseState]]'] = 'rejected'
    this['[[PromiseResult]]'] = error
    // 将执行this.rejectFn(val)的时机放入宏任务中
    // 确保在then之后做判断
    setTimeout(() => {
      // 依次执行该promise实例下的多个.then对应的reject方法
      this.rejectFnList.forEach(rejectFnItem => rejectFnItem(error))
    }, 0)
  }

  // xpromise实例方法
  then = (onResolved, onReject) => {
    // 将成功或失败的两个函数保存至当前xpromise实例
    return new XPromise((resolve, reject) => {
      // 在这里需要把当前这个promise的结果拿到
      // resolveFn是需要push到函数队列中的,接受当前promise实例的值
      const resolveFn = (val) => {
        const result = onResolved && onResolved(val)
        if (result instanceof XPromise) {
          // result 既然是xpromise实例
          // 那这个xpromise的结果就可以从.then中获取
          result.then(val => resolve(val))
        } else {
          resolve(result)
        }
      }
      this.resolveFnList.push(resolveFn)

      const rejectFn = (error) => {
        onReject && onReject(error)
        reject(error)
      }
      this.rejectFnList.push(rejectFn)
    })
  }
}
export default XPromise

在这里插入图片描述
我们可以看到最红在浏览器中执行的结果也是符合预期的

总结

我们使用js来实现了promise中的状态、值以及promise中.then函数的使用。后续会再总计诶归纳promise中其他方法的实现

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

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

相关文章

JSP原理以及基本语法

1、JSP原理 什么是JSP&#xff1f; Java Server Pages&#xff1a;Java服务器页面&#xff0c;和Servlet一样是动态Web技术&#xff01; 和HTML的区别&#xff1f; HTML是静态页面。在JSP页面中可以嵌入Java代码&#xff0c;为用户提供动态的数据。 JSP 和 Servlet 的关系…

枚举一个进程中的所有线程

在 Win32 开发中&#xff0c;如果需要获取程序运行过程中的一些较为底层的信息&#xff0c;你可能需要使用到 Tool Helper 库。但我愿意称之它为 Win32 中的 “害群之马”。何解&#xff1f; Tool Helper 库在 16 位 Windows 时代就已经存在了&#xff0c;这个库主要用来提供一…

今天给我的Ubuntu服务器挂在了一个4T的硬盘却只能识别到2T,原来是因为这!涨知识了

前言 今天买的4T机械硬盘到了&#xff0c;准备给我的服务器加装上&#xff0c;用来作为Nextcloud的存储硬盘。把硬盘安装好后就迫不及待的进行挂载&#xff0c;挂载的操作倒是挺顺利的&#xff0c;但是无论怎么操作Ubuntu系统识别到的大小居然都是2T&#xff0c;最后没办法&am…

chatgpt赋能python:开方在Python中的用法

开方在Python中的用法 开方是数学中常见的一种运算&#xff0c;用于求一个数的平方根。在Python中&#xff0c;开方运算可以通过使用math模块中的sqrt函数来实现。本文将介绍开方运算的概念、Python中的应用以及一些常见问题的解决方法。 开方的概念 开方是指&#xff0c;对…

chatgpt赋能python:在Python中运行程序的方法介绍

在Python中运行程序的方法介绍 Python是一种广泛使用的编程语言&#xff0c;也是人工智能和数据科学领域的首选。在这篇SEO文章中&#xff0c;我们将介绍Python中运行程序的几种方法。 1. 在Python环境中运行程序 Python环境是一个Python解释器及其标准库的集合。为了在Pyth…

Redis7【⑥ Redis复制(replica)】

Redis复制 Redis 复制&#xff08;Replication&#xff09;是 Redis 的一项核心功能&#xff0c;用于将一个 Redis 数据库的所有数据复制到另一个 Redis 实例上。Redis 复制可以提高系统的可用性、可靠性和扩展性&#xff0c;使得在发生故障时可以快速地恢复数据。 Redis 复制…

【TiDB v7.1.0】资源管控调研及评测

作者&#xff1a; angryart 原文来源&#xff1a; https://tidb.net/blog/ad24240a 多租户是什么 有语云&#xff0c;食在广州&#xff0c;玩在杭州&#xff0c;死在柳州&#xff0c;广东人除了天上飞的飞机不吃&#xff0c;地上走的坦克不吃&#xff0c;其它的什么都吃&am…

Mybatis面试题--MyBatis一级缓存,二级缓存

Mybatis的一级、二级缓存用过吗&#xff1f; 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存&#xff0c;其存储作用域为 Session&#xff0c;当Session进行flush或close之后&#xff0c;该Session中的所有Cache就将清空&#xff0c;默认打开一级缓存 二级缓存 是基于n…

Python将多维列表「拉伸」为一维列表的10种方式

来源&#xff1a;投稿 作者&#xff1a;Fairy 编辑&#xff1a;学姐 在Python编程中&#xff0c;列表是一种常用的数据类型。当我们遇到了一个嵌套列表&#xff0c;如果想将它扁平化为一维列表&#xff0c;就可以使用下面10种方法之一来实现这个需求。 1. 使用两层循环遍历 l…

【记录】实践场景

Apache Doris 在京东搜索实时 OLAP 探索与实践 https://doris.apache.org/zh-CN/blog/JD_OLAP/ 通过对比开源的几款实时OLAP引擎&#xff0c;我们发现doris和clickhouse能够满足我们的需求&#xff0c;但是clickhouse的并发度太低是个潜在的风险&#xff0c;而且clickhouse的数…

已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。

错误提示&#xff1a; 一般只有下面几种方法 百度经验解决方法 http://jingyan.baidu.com/article/90bc8fc859b481f653640cac.html http://jingyan.baidu.com/article/25648fc1bfd4a29190fd0067.html 2.第二种方法 检测问题所在&#xff1a; 下载LeoMoon CPU-V 检查一下CP…

小程序本地生活

2023年7月1号 感觉就是视频要快点看不完 不然哪天接口又失效了 Page({/*** 页面的初始数据*/data: {// 存放轮播图的数据swiperList:[],// 存放九宫格的数据gridList:[]},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.getSwiperList()this.getGridList()},// 获…

【GIS】阿里AI Earth选择内置地图

说明 aie.Map&#xff0c;构造一个地图组件Map对象&#xff0c;用于可视化渲染计算结果。坐标系固定为EPSG:4326。 阿里AI Earth中&#xff0c;坐标系默认为EPSG:4326 效果 import aie aie.Authenticate() aie.Initialize() my_province aie.FeatureCollection(China_Provin…

【Python】Python基础笔记

Python基础笔记 数据的输入和输出 print("数据") # 这是数据的输出 name input() # 这是数据的输入&#xff0c;并将输入的数据赋值给name。而且无论输入的何种类型的数据&#xff0c;最终的结果都是 字符串 类型的数据pint 输出不换行&#xff1a; # print 输出…

结合ace编辑器实现MapboxGL热力图样式在线配置

概述 MapboxGL热力图的配置参数并不多&#xff0c;但是有时候为了或得一个比较好用的热力图配置参数&#xff0c;我们不得不改代码再预览&#xff0c;显得尤为麻烦&#xff0c;为方便配置&#xff0c;实现实时预览&#xff0c;本文使用ace实现了一个热力图样式在线配置页面。 …

MSF之信息收集及漏洞利用

MSF之信息收集及漏洞利用 一、Metasploit简介二、Metasploit安装三、安装postgresql数据库四、KaIi-msfdb-Postgresql报错排查处理五、Metasploit-启动六、Metasploit-目录结构六、Metasploit-模块七、Metasploit-信息收集7.1、db_nmap/nmap7.2、Metasploit auxiliary7.2.1、端…

【STM32】步进电机及其驱动(ULN2003驱动28BYJ-48丨按键控制电机旋转)

本篇文章包含的内容 一、步进电机的结构和工作原理1.1 步进控制系统的组成1.2 步进电机简介1.3 步进电机的分类1.4 步进电机的工作原理1.4.1 单极性步进电机&#xff08;5线4相&#xff09;1.4.2 双极性步进电机&#xff08;4线2相&#xff09;1.4.3 细分器驱动原理 1.5 步进电…

hcia回顾复习

一、OSI七层参考模型 OSI/RM 开放式系统互联参考模型 由ISO ---- 国际标准化组织 — 1979提出 核心思想 分层 :上层协议再下层协议提供服务的基础上再提供增值服务。 应用层 — 提供各种应用服务.可以将抽象语言转换为编码 .应用程序 APP&#xff1a;通过人机交互提供&#xff…

Win10打字输入法不显示输入框怎么办?

Win10的打字输入法是我们日常计算机使用中必不可少的工具之一&#xff0c;然而&#xff0c;有时候在使用过程中可能会遇到打字输入法不显示输入框的问题&#xff0c;这给我们的输入和操作带来了很大的困扰&#xff0c;如果您也遇到了这个问题&#xff0c;不要担心&#xff0c;以…

Linux--获取某个区间文本的指令:head和tail

Linux--获取文本前n行的指令&#xff1a;head 语法&#xff1a; head 选项 文件名 功能&#xff1a; head 用来显示档案的开头至标准输出中&#xff0c;默认head命令打印其相应文件的开头10行。 选项&#xff1a; -n <行数> 显示的行数 示例&#xff1a; ①生成默…