前端为什么有的接口明明是成功回调却执行了.catch失败回调_前端进阶高薪必看-手写源码篇(高频技术点)...

前言

此系列作为笔者之前发过的前端高频面试整理的补充 会比较偏向中高前端面试问题 当然大家都是从新手一路走过来的 感兴趣的朋友们都可以看哈

初衷

我相信不少同学面试的时候最怕的一个环节就是手写代码 大家一定听过这句话talk is cheap, show me the code 没事 此文章不仅包含了前端经典的手写源码面试题 还包含了大量的分析和引导 希望能帮助大家更好的食用(欢迎评论 不定时更新补充题库)

注意

本文所有的手写源码实现都是基于 es6 的 不想用原生去实现原因如下:一方面是网上太多原生实现的方案了 另一方面是我们要面向未来编程 多使用 es6 的特性更加贴合实际工作

1 promise

先思考?

  1. promise 是什么?

异步回调解决方案

  1. promise 如何保证异步执行完了再去执行后面的代码?

使用 then 关键字 then 接受两个参数 第一个参数(函数)会在 promise resolve 之后执行 第二个参数(函数)会在 promise reject 之后执行

  1. 为什么能在异步事件执行完成的回调之后再去触发 then 中的函数?

引入事件注册机制(将 then 中的代码注册事件 当异步执行完了之后再去触发事件)

  1. 怎么保证 promise 链式调用 形如 promise.then().then()

每个 then 返回的也是一个 promise 对象

  1. 怎么知道异步事件执行完毕或者执行失败?

需要状态表示


具体实现如下

//这里使用es6 class实现class Mypromise {  constructor(fn) {    // 表示状态    this.state = "pending";    // 表示then注册的成功函数    this.successFun = [];    // 表示then注册的失败函数    this.failFun = [];    let resolve = val => {      // 保持状态改变不可变(resolve和reject只准触发一种)      if (this.state !== "pending") return;      // 成功触发时机  改变状态 同时执行在then注册的回调事件      this.state = "success";      // 为了保证then事件先注册(主要是考虑在promise里面写同步代码) promise规范 这里为模拟异步      setTimeout(() => {        // 执行当前事件里面所有的注册函数        this.successFun.forEach(item => item.call(this, val));      });    };    let reject = err => {      if (this.state !== "pending") return;      // 失败触发时机  改变状态 同时执行在then注册的回调事件      this.state = "fail";      // 为了保证then事件先注册(主要是考虑在promise里面写同步代码) promise规范 这里模拟异步      setTimeout(() => {        this.failFun.forEach(item => item.call(this, err));      });    };    // 调用函数    try {      fn(resolve, reject);    } catch (error) {      reject(error);    }  }  // 实例方法 then  then(resolveCallback, rejectCallback) {    // 判断回调是否是函数    resolveCallback =      typeof resolveCallback !== "function" ? v => v : resolveCallback;    rejectCallback =      typeof rejectCallback !== "function"        ? err => {            throw err;          }        : rejectCallback;    // 为了保持链式调用  继续返回promise    return new Mypromise((resolve, reject) => {      // 将回调注册到successFun事件集合里面去      this.successFun.push(val => {        try {          //    执行回调函数          let x = resolveCallback(val);          //(最难的一点)          // 如果回调函数结果是普通值 那么就resolve出去给下一个then链式调用  如果是一个promise对象(代表又是一个异步) 那么调用x的then方法 将resolve和reject传进去 等到x内部的异步 执行完毕的时候(状态完成)就会自动执行传入的resolve 这样就控制了链式调用的顺序          x instanceof Mypromise ? x.then(resolve, reject) : resolve(x);        } catch (error) {          reject(error);        }      });      this.failFun.push(val => {        try {          //    执行回调函数          let x = rejectCallback(val);          x instanceof Mypromise ? x.then(resolve, reject) : reject(x);        } catch (error) {          reject(error);        }      });    });  }  //静态方法  static all(promiseArr) {    let result = [];    //声明一个计数器 每一个promise返回就加一    let count = 0    return new Mypromise((resolve, reject) => {      for (let i = 0; i < promiseArr.length; i++) {        promiseArr[i].then(          res => {          //这里不能直接push数组  因为要控制顺序一一对应(感谢评论区指正)            result[i] = res            count++            //只有全部的promise执行成功之后才resolve出去            if (count === promiseArr.length) {              resolve(result);            }          },          err => {            reject(err);          }        );      }    });  }  //静态方法  static race(promiseArr) {    return new Mypromise((resolve, reject) => {      for (let i = 0; i < promiseArr.length; i++) {        promiseArr[i].then(          res => {          //promise数组只要有任何一个promise 状态变更  就可以返回            resolve(res);          },          err => {            reject(err);          }        );      }    });  }}// 使用let promise1 = new Mypromise((resolve, reject) => {  setTimeout(() => {    resolve(123);  }, 2000);});let promise2 = new Mypromise((resolve, reject) => {  setTimeout(() => {    resolve(1234);  }, 1000);});// Mypromise.all([promise1,promise2]).then(res=>{//   console.log(res);// })// Mypromise.race([promise1, promise2]).then(res => {//   console.log(res);// });promise1  .then(    res => {      console.log(res); //过两秒输出123      return new Mypromise((resolve, reject) => {        setTimeout(() => {          resolve("success");        }, 1000);      });    },    err => {      console.log(err);    }  )  .then(    res => {      console.log(res); //再过一秒输出success    },    err => {      console.log(err);    }  );复制代码

扩展:如何取消 promise

先思考?

怎么才能取消已经发起的异步呢?

Promise.race()方法可以用来竞争 Promise 谁的状态先变更就返回谁那么可以借助这个 自己包装一个 假的 promise 与要发起的 promise 来实现


具体实现如下

function wrap(pro) {  let obj = {};  // 构造一个新的promise用来竞争  let p1 = new Promise((resolve, reject) => {    obj.resolve = resolve;    obj.reject = reject;  });  obj.promise = Promise.race([p1, pro]);  return obj;}let testPro = new Promise((resolve, reject) => {  setTimeout(() => {    resolve(123);  }, 1000);});let wrapPro = wrap(testPro);wrapPro.promise.then(res => {  console.log(res);});wrapPro.resolve("被拦截了");复制代码

2 防抖节流

先思考

  1. 防抖和节流区别

防抖是 N 秒内函数只会被执行一次,如果 N 秒内再次被触发,则重新计算延迟时间(举个极端的例子 如果 window 滚动事件添加了防抖 2s 执行一次 如果你不停地滚动 永远不停下 那这个回调函数就永远无法执行)

节流是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行(还是滚动事件 如果你一直不停地滚动 那么 2 秒就会执行一次回调)

  1. 防抖怎么保证

事件延迟执行 并且在规定时间内再次触发需要清除 这个很容易就想到了 setTimeout

  1. 节流怎么保证

在单位时间内触发了一次就不再生效了 可以用一个 flag 标志来控制


具体实现如下

// 防抖function debounce(fn, delay=300) {  //默认300毫秒  let timer;  return function() {    var args = arguments;    if (timer) {      clearTimeout(timer);    }    timer = setTimeout(() => {      fn.apply(this, args); // 改变this指向为调用debounce所指的对象    }, delay);  };}window.addEventListener(  "scroll",  debance(() => {    console.log(111);  }, 1000));// 节流//方法一:设置一个标志function throttle(fn, delay) {  let flag = true;  return () => {    if (!flag) return;    flag = false;    timer = setTimeout(() => {      fn();      flag = true;    }, delay);  };}//方法二:使用时间戳function throttle(fn, delay) {  let startTime = new Date();  return () => {    let endTime = new Date();    if (endTime - startTime >= delay) {      fn();      startTime = endTime;    } else {      return;    }  };}window.addEventListener(  "scroll",  throttle(() => {    console.log(111);  }, 1000));复制代码

防抖节流属于性能优化的一点 更多性能优化扩展请点击 性能优化

30f09cfe711f4fb6aeb17621892cc75a.png

3 EventEmitter(发布订阅模式--简单版)

先思考?

  1. 什么是发布订阅模式

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知

  1. 怎么实现一对多

既然一对多 肯定有一个事件调度中心用来调度事件 订阅者可以注册事件(on)到事件中心 发布者可以发布事件(emit)到调度中心 订阅者也可以取消订阅(off)或者只订阅一次(once)


具体实现如下

// 手写发布订阅模式 EventEmitterclass EventEmitter {  constructor() {    this.events = {};  }  // 实现订阅  on(type, callBack) {    if (!this.events) this.events = Object.create(null);    if (!this.events[type]) {      this.events[type] = [callBack];    } else {      this.events[type].push(callBack);    }  }  // 删除订阅  off(type, callBack) {    if (!this.events[type]) return;    this.events[type] = this.events[type].filter(item => {      return item !== callBack;    });  }  // 只执行一次订阅事件  once(type, callBack) {    function fn() {      callBack();      this.off(type, fn);    }    this.on(type, fn);  }  // 触发事件  emit(type, ...rest) {    this.events[type] && this.events[type].forEach(fn => fn.apply(this, rest));  }}// 使用如下const event = new EventEmitter();const handle = (...rest) => {  console.log(rest);};event.on("click", handle);event.emit("click", 1, 2, 3, 4);event.off("click", handle);event.emit("click", 1, 2);event.once("dbClick", () => {  console.log(123456);});event.emit("dbClick");event.emit("dbClick");复制代码

4 call、apply、bind

先思考?

  1. call 用法

第一个参数 可以改变调用函数的 this 指向 第二个以及之后的参数为传入的函数的参数

let obj = {  a: 1};function fn(name, age) {  console.log(this.a); //1  console.log(name);  console.log(age);}fn.call(obj, "我是 lihua", "18");复制代码
  1. 怎么改变 this 指向呢

根据 this 特性 对象的方法调用 那么方法内部的 this 就指向这个对象

let obj = {  a: 1,  fn(name, age) {    console.log(this.a); //1    console.log(name);    console.log(age);  }};obj.fn("我是lihua", "18");复制代码
  1. 怎么获取传入的不定参数呢

利用 es6 ...args 剩余参数获取方法(rest)


具体实现如下

Function.prototype.myCall = function(context, ...args) {  if (!context || context === null) {    context = window;  }  // 创造唯一的key值  作为我们构造的context内部方法名  let fn = Symbol();  context[fn] = this; //this指向调用call的函数  // 执行函数并返回结果 相当于把自身作为传入的context的方法进行调用了  return context[fn](...args);};// apply原理一致  只是第二个参数是传入的数组Function.prototype.myApply = function(context, args) {  if (!context || context === null) {    context = window;  }  // 创造唯一的key值  作为我们构造的context内部方法名  let fn = Symbol();  context[fn] = this;  // 执行函数并返回结果  return context[fn](...args);};//测试一下 call 和 applylet obj = {  a: 1};function fn(name, age) {  console.log(this.a);  console.log(name);  console.log(age);}fn.myCall(obj, "我是lihua", "18");fn.myApply(obj, ["我是lihua", "18"]);let newFn = fn.myBind(obj, "我是lihua", "18");newFn();//bind实现要复杂一点  因为他考虑的情况比较多 还要涉及到参数合并(类似函数柯里化)Function.prototype.myBind = function (context, ...args) {  if (!context || context === null) {    context = window;  }  // 创造唯一的key值  作为我们构造的context内部方法名  let fn = Symbol();  context[fn] = this;  let _this = this  //  bind情况要复杂一点  const result = function (...innerArgs) {    // 第一种情况 :若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符使用,则不绑定传入的 this,而是将 this 指向实例化出来的对象    // 此时由于new操作符作用  this指向result实例对象  而result又继承自传入的_this 根据原型链知识可得出以下结论    // this.__proto__ === result.prototype   //this instanceof result =>true    // this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true    if (this instanceof _this === true) {      // 此时this指向指向result的实例  这时候不需要改变this指向      this[fn] = _this      this[fn](...[...args, ...innerArgs]) //这里使用es6的方法让bind支持参数合并      delete this[fn]    } else {      // 如果只是作为普通函数调用  那就很简单了 直接改变this指向为传入的context      context[fn](...[...args, ...innerArgs]);      delete context[fn]    }  };  // 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法  // 实现继承的方式一:  构造一个中间函数来实现继承  // let noFun = function () { }  // noFun.prototype = this.prototype  // result.prototype = new noFun()  // 实现继承的方式二: 使用Object.create  result.prototype = Object.create(this.prototype)  return result};//测试一下function Person(name, age) {  console.log(name); //'我是参数传进来的name'  console.log(age); //'我是参数传进来的age'  console.log(this); //构造函数this指向实例对象}// 构造函数原型的方法Person.prototype.say = function() {  console.log(123);}let obj = {  objName: '我是obj传进来的name',  objAge: '我是obj传进来的age'}// 普通函数function normalFun(name, age) {  console.log(name);   //'我是参数传进来的name'  console.log(age);   //'我是参数传进来的age'  console.log(this); //普通函数this指向绑定bind的第一个参数 也就是例子中的obj  console.log(this.objName); //'我是obj传进来的name'  console.log(this.objAge); //'我是obj传进来的age'}// 先测试作为构造函数调用// let bindFun = Person.myBind(obj, '我是参数传进来的name')// let a = new bindFun('我是参数传进来的age')// a.say() //123// 再测试作为普通函数调用let bindFun = normalFun.myBind(obj, '我是参数传进来的name') bindFun('我是参数传进来的age')复制代码

bind 实现 运用原型链相关知识 如果对 js 原型链和继承不是很熟悉 请点传送门

5 new 操作符

先思考?

  1. new 用法是什么?

从构造函数创造一个实例对象 构造函数的 this 指向为创造的实例函数 并且可以使用构造函数原型属性和方法

function Person(name, age) {  this.name = name;  this.age = age;}Person.prototype.say = function() {  console.log(this.age);};let p1 = new Person("lihua", 18);console.log(p1.name);p1.say();复制代码
  1. 怎么实现 this 指向改变?

call apply

  1. 怎么实现构造函数原型属性和方法的使用

原型链 原型继承


具体实现如下

function myNew(fn, ...args) {  // 1.创造一个实例对象  let obj = {};  // 2.生成的实例对象继承构造函数原型  // 方法一 粗暴的改变指向 完成继承  obj.__proto__ = fn.prototype;  // 方法二 利用Object.create实现  // obj=Object.create(fn.prototype)  // 3.改变构造函数this指向为实例对象  let result = fn.call(obj, ...args);  // 4. 如果构造函数执行的结果返回的是一个对象或者函数,那么返回这个对象或函数  if ((result && typeof result === "object") || typeof result === "function") {    return result;  }  //不然直接返回boj  return obj;}// 测试一下function Person(name, age) {  this.name = name;  this.age = age;}Person.prototype.say = function() {  console.log(this.age);};let p1 = myNew(Person, "lihua", 18);console.log(p1.name);console.log(p1);p1.say();复制代码

对原型链深入理解学习 建议看看 传送门

6 instanceof

先思考?

  1. instanceof 原理?

右侧对象的原型对象(prototype )是否在左侧对象的原型链上面

  1. 怎么遍历左侧对象的原型链是关键点?

while(true) 一直遍历 直到原型链的尽头 null 都没有相等就说明不存在 返回 false


具体实现如下

function myInstanceof(left, right) {  let leftProp = left.__proto__;  let rightProp = right.prototype;  // 一直会执行循环  直到函数return  while (true) {    // 遍历到了原型链最顶层    if (leftProp === null) {      return false;    }    if (leftProp === rightProp) {      return true;    } else {      // 遍历赋值__proto__做对比      leftProp = leftProp.__proto__;    }  }}// 测试一下let a = [];console.log(myInstanceof(a, Array));复制代码

7 深拷贝

先思考?

  1. 什么是深拷贝?

js 对引用类型的数据进行复制的时候,深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突

  1. 怎么样才能全部拷贝?

递归遍历 直到数据类型不是引用类型才进行赋值操作


具体实现如下

// 定义一个深拷贝函数  接收目标target参数function deepClone(target) {    // 定义一个变量    let result;    // 如果当前需要深拷贝的是一个对象的话    if (typeof target === 'object') {    // 如果是一个数组的话        if (Array.isArray(target)) {            result = []; // 将result赋值为一个数组,并且执行遍历            for (let i in target) {                // 递归克隆数组中的每一项                result.push(deepClone(target[i]))            }         // 判断如果当前的值是null的话;直接赋值为null        } else if(target===null) {            result = null;         // 判断如果当前的值是一个RegExp对象的话,直接赋值        } else if(target.constructor===RegExp){            result = target;        }else {         // 否则是普通对象,直接for in循环,递归赋值对象的所有值            result = {};            for (let i in target) {                result[i] = deepClone(target[i]);            }        }     // 如果不是对象的话,就是基本数据类型,那么直接赋值    } else {        result = target;    }     // 返回最终结果    return result;}复制代码

扩展:利用JSON的方法实现简单的深拷贝

let targetObj = JSON.parse(JSON.stringify(sourceObj))复制代码

但是它有局限性

  • 不可以拷贝 undefined , function, RegExp 等等类型的
  • 会抛弃对象的 constructor,所有的构造函数会指向 Object
  • 对象有循环引用,会报错

源自:https://juejin.im/post/5eb8f5cdf265da7bd44254b4

声明:文章著作权归作者所有,如有侵权,请联系小编删除。

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

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

相关文章

C/C++函数指针与指针函数

前面说的话 面试的时候&#xff0c;经常有面试官问这个问题&#xff0c;在Linux内核里面也是经常被使用的&#xff0c;在看很多大神的代码里面&#xff0c;我们也经常遇到函数指针与指针函数&#xff0c;一样&#xff0c;如果你自己没问题了&#xff0c;就不用往下看了。 定义…

jsp人事管理系统_Jsp+Ssm+Mysql实现的医院人事管理系统源码附带视频运行教程

项目地址&#xff1a;jspssmmysql实现的医院人事管理系统源码附带视频运行教程|猿来入此【beta】多用户版IT项目教程源码分享网站​www.yuanlrc.com今天给大家演示的是一款由jspssm&#xff08;springspringMVCmybatis&#xff09;实现的医院人事管理系统&#xff0c;系统比较简…

RK3288/RK3399 CPU定频方法

直接上方法 查看cpu能支持的频率 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies 写入userspace说明要用户设定频率 echo userspace > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor 写入上面列出的cpu频率 echo 1608000 > …

notepad++正则表达式去掉关键字所在行

如下图 1、选择正则表达式 2、选择匹配大小写 3、^(.*)KERNEL(.*)$\n 加上\n就是把去除的行删除&#xff0c;不加就算把删除的行替换为空格

深度学习·理论篇(2023版)·第003篇深度学习和计算机视觉中的基础数学知识02:特征向量和特征值+矩阵乘法的几何意义(2)+奇异值分解+线性可分性和维度+非线性变换

&#x1f495;恭喜本博客浏览量达到两百万&#xff0c;CSDN内容合伙人&#xff0c;CSDN人工智能领域实力新星~ &#x1f9e1;本文章为2021版本迭代更新版本&#xff0c;在结合有效知识的基础上对文章进行合理的增加&#xff0c;使得整个文章时刻顺应时代需要 &#x1f9e1;本…

Oracle 控制文件管理

控制文件是一个很小的二进制文件(10MB左右)&#xff0c;含有数据库结构信息&#xff0c;包括数据文件和日志文件信息。控制文件在数据库创建时被自动创建&#xff0c;并在数据库发生物理变数时更新。控制文件被不断更新&#xff0c;在任何时候都要保证控制文件可用&#xff0c;…

数组超过预设的最大数组大小_工作表数组大小的扩展及意义

朋友们好&#xff0c;今日给大家继续讲解VBA数组与字典解决方案的第17讲&#xff0c;数组大小的扩充问题。这一讲的内容相对比较简单&#xff0c;在之前的章节中讲了数组与数组的计算规律&#xff0c;也是利用了数组的扩展原理。其实&#xff0c;两个数组计算时&#xff0c;参与…

Android ANR 实例分析

什么是ANR&#xff1f; 以下四个条件都可以造成ANR发生&#xff1a; InputDispatching Timeout&#xff1a;5秒内无法响应屏幕触摸事件或键盘输入事件BroadcastQueue Timeout &#xff1a;在执行前台广播&#xff08;BroadcastReceiver&#xff09;的onReceive()函数时10秒没…

【GIT 基础篇六】分支管理(创建与合并)

上篇我们整理了如何创建远程仓库&#xff0c;以及如何将本地文件上传至远程仓库&#xff0c;仓库创建好了&#xff0c;我们接下来就要准备开发了&#xff0c;对于使用git而言&#xff0c;通常的习惯就是一人一个分支&#xff0c;等测试无误再合并&#xff1b;又或者根据需求创建…

git 命令汇总

瞎扯 最近有几个留言想让写下git的内容&#xff0c;git是一个工具&#xff0c;主要是用来管理码农的代码的&#xff0c;理由很简单&#xff0c;码农写的代码太多&#xff0c;自己都不知道可能哪里出现了Crash。Linux也是因为git的出现&#xff0c;可以让世界上越来越多的人维护…

我的最佳队友之K8无线蓝牙键盘深度使用测评( Keychron K8 )

K8 无线蓝牙键盘深度使用测评&#xff08; Keychron K8 &#xff09;——500 元左右最适配 Mac 电脑的机械键盘 0.键盘参数&#xff1a; 首先我们在实际测评之前&#xff0c;看下这个键盘的具体参数&#xff0c;心里有个大致的了解~ 87键 国产佳达隆G轴 可选茶轴/红轴/青轴 蓝…

你见过哪些操蛋的代码?

NO.1#define TRUE FALSE //Happy debugging suckers快乐的去调试你的代码吧&#xff0c;哈哈NO.2#define NULL (::rand() % 2) // would be quite nice aswell嗯&#xff0c;这个代码也很不错NO.3#define if( if(!卧槽&#xff0c;这个代码更加叼&#xff0c;哈哈&#xff…

后序线索树怎样画图_算法新解刘新宇(二)二叉搜索树:数据结构中的“hello world”...

二叉搜索树BST定义&#xff1a;基于广义二叉树&#xff0c;一颗二叉树定义&#xff1a;或者为空 或者包含三部分&#xff1a;一个值&#xff0c;一个左分支和一个右分支。这两个分支也都是二叉树分支。一颗二叉搜索树是满足下面条件的二叉树&#xff1a;所有左分支的值都小于本…

Android 亮屏速度分析总结

前面聊的 最近在调试项目的亮屏速度&#xff0c;我们希望在按下power键后到亮屏这个时间能达到500MS以内&#xff0c;在Rockchip 3399和3288上面的时间都不能达到要求&#xff0c;因此引发了一系列的调试之路。 计算按下power键到亮屏的时间 Android 唤醒时间统计 刚开始的时…

英语学习中总结的阅读、段落匹配、选词填空技巧

1 阅读题 一般五道题都是围绕主旨来问的&#xff0c;所以后四个问题也能帮助第一题的解答&#xff0c;找共有词~~~串起来 文章一般都是新旧观点的碰撞&#xff0c;所以有时候他问的是旧观点&#xff0c;要看清楚他问的是新观点还是旧观点&#xff0c;这是个陷阱~ 2 段落匹配 反…

sql 账号查询一个表查询权限_一个查询语句引发的问题以及巨型表相关操作探索与思考...

背景&#xff1a;关于这个标题想了试了好几个总觉得欠那么点意思。大致情况是&#xff0c;在某服务支持中&#xff0c;1张大表4.5T左右&#xff0c;该表也是分区表。其中一个执行频繁的SQL写法有很大问题&#xff0c;导致巨表全量扫描&#xff0c;造成IO负载很大&#xff0c;业…

Android 亮屏速度分析

前面聊的最近在调试项目的亮屏速度&#xff0c;我们希望在按下power键后到亮屏这个时间能达到500MS以内&#xff0c;在Rockchip 3399和3288上面的时间都不能达到要求&#xff0c;因此引发了一系列的调试之路。计算按下power键到亮屏的时间Android 唤醒时间统计刚开始的时候&…

container_of实例

1 前面说的 container_of 在linux内核代码里面使用非常多&#xff0c;对于喜欢linux编程的同学来说&#xff0c;对这个函数要非常清楚他的使用方法&#xff0c;而且还要知道他的原理&#xff0c;这对以后看内核代码&#xff0c;写内核驱动的帮助都非常大&#xff0c;当然&…

Git 分布式版本控制工具 03Git常用命令:Git全局设置+本地与远程仓库操作获取Git仓库+标签操作+忽略名单+工作区、暂存区、版本库+分支操作+暂时保存

Git常用命令目录4 Git常用命令4.1 Git全局设置4.2 获取Git仓库4.2.1 在本地初始化Git仓库4.2.2 从远程仓库克隆4.3 常见的概念&#xff1a;工作区、暂存区、版本库4.4 常见的概念&#xff1a;Git工作区中文件的状态4.5 本地仓库操作4.5.1 git status4.5.2 git add4.5.3 git res…

matlab dir函数_MATLAB自动管理文件

MATLAB自动管理文件1. MATLAB中路径设置(1)cd:用于切换当前工作目录示例&#xff1a;将当前工作目录切换到D:\Documents\MATLAB\Matlab test\study下。代码:cd (D:\Documents\MATLAB\Matlab test\study)(2)path:用于对搜索路径的操作示例&#xff1a;先查看当前所有的文件路径&…