手写promis(1)

news2024/11/14 2:17:59

目录

前言

核心功能--构造函数 

核心功能--状态及原因

then方法

成功和失败回调

异步及多次调用

异步任务--核心api

Promise.then:

queueMicrotask:

MutationObserver:

setImmediate:

setTimeout:

异步任务---函数封装


前言

Promise(承诺)是一种用于处理异步操作的JavaScript编程技术。它是一种代表一个尚未完成的操作的对象,该操作可能会在将来的某个时刻完成或失败。Promise提供了一种更结构化和可维护的方式来处理异步代码,特别是在处理网络请求、文件I/O、定时器等操作时非常有用。

Promise对象有三种状态:

  1. Pending(进行中):初始状态,表示操作尚未完成或失败。
  2. Fulfilled(已完成):表示操作成功完成。
  3. Rejected(已失败):表示操作失败。

Promise对象具有两个重要的方法:

  1. then(): 用于注册回调函数,当Promise状态变为Fulfilled时执行。
  2. catch(): 用于注册回调函数,当Promise状态变为Rejected时执行。

使用Promise,可以更清晰地定义异步操作的工作流程,避免了回调地狱(Callback Hell)的问题,使代码更易于理解和维护。以下是一个简单的Promise示例:

const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const randomValue = Math.random();
    if (randomValue > 0.5) {
      resolve("操作成功");
    } else {
      reject("操作失败");
    }
  }, 1000);
});

myPromise
  .then(result => {
    console.log(result); // 在操作成功时执行
  })
  .catch(error => {
    console.error(error); // 在操作失败时执行
  });

这个示例创建了一个Promise对象,模拟了一个异步操作,并根据随机值决定是成功还是失败。通过.then().catch()方法,我们可以分别处理成功和失败的情况。这使得异步代码的处理更加结构化和可控。

手写原来步骤

核心功能--构造函数 

  1. 定义类(Define the class): 这里定义了一个名为MyPromise的类,用于创建自定义Promise对象。

  2. 添加构造函数(Add a constructor): 在构造函数中,通过constructor方法定义了一个新的MyPromise对象。当创建MyPromise对象时,会执行构造函数。构造函数接受一个函数func作为参数,这个函数在创建MyPromise对象时传入。

  3. 定义resolve/reject(Define resolve and reject functions): 在构造函数中,定义了resolvereject函数,它们分别用于处理Promise的成功和失败情况。resolve函数用于处理成功情况,它接受一个参数result,表示成功的原因。reject函数用于处理失败情况,它也接受一个参数result,表示失败的原因。

  4. 执行回调函数(Execute the callback function): 最后,构造函数中调用了传入的func函数,这个函数接受resolvereject作为参数。这意味着在创建MyPromise对象时,会执行传入的回调函数,并在适当的时候调用resolvereject函数来处理异步操作的结果

/**
 * 构造函数
 * 1. 定义类
 * 2. 添加构造函数
 * 3. 定义reslove/reject
 * 4. 执行回调函数
 */

//1.定义类
class MyPromise {
    // 2.添加构造函数 new时会执行 constructor 传入回调函数
    constructor(func) {
        // 3.func 接受两个行参 成功回调(成功原因),失败回调(失败原因)
        // resolve:<Function>(result:<any>)  reject:<Function>(result:<any>) 
        const resolve = (result) => {
            console.log('resolve执行了--', result);
        }
        const reject = (result) => {
            console.log('reject执行了--', result);
        }

        // 4. 执行回调函数
        func(resolve, reject)
    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {
    console.log('执行回调函数');
    // resolve('success')
    reject('error')
})

核心功能--状态及原因

  1. 添加实例属性状态(pending / fulfilled / rejected)(默认为等待)

  2. 添加实例属性原因(默认为undefined)

  3. 调整resolve函数和reject函数 resolvereject函数改变状态和保存原因,这是Promise的核心功能之一。

  4. 添加状态检查:在resolvereject函数中,添加状态检查来确保状态只能从pending改变一次。这可以防止状态被多次改变。
/**
 * 状态及原因
 * 1. 添加状态 pending / fulfilled / rejected
 * 2. 添加原因
 * 3. 调整reslove/reject
 * 4. 状态不可逆
 */

//通过变量保存状态,方便使用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    // 1. 添加实例属性 状态(pending / fulfilled / rejected)(默认为等待)
    state = PENDING
    // 2. 添加实例属性 原因(默认为undefined)
    result = undefined
    constructor(func) {
        // this 箭头函数this-->上级作用域(构造函数)-->  实例 
        // 3. 调整reslove pending-- > fulfilled 添加原因
        const resolve = (result) => {
            // 4. 状态不可逆
            if (this.state == PENDING) {
                this.state = FULFILLED
                this.result = result
            }
        }

        // 3. reject pending-- > rejected 添加原因
        const reject = (result) => {
            if (this.state == PENDING) {
                this.state = REJECTED
                this.result = result
            }
        }

        func(resolve, reject)
    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {

    resolve('success')
    // reject('error')
})

then方法

成功和失败回调

  1. 添加实例方法(then)
  2. 参数判断(参考文档)

如果是个函数 执行回调函数 

如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),它只是简单地将兑现值向前传递。

如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; }),它会抛出它收到的拒绝原因。

3.判断状态执行成功回调函数or失败回调函数(实例化完成后状态已经确定)

/**
 * 成功和失败回调
 * 1. 添加实例方法
 * 2. 参数判断(参考文档)
 *  2.1. 执行成功回调
 *  2.2. 执行失败回调
 */

//通过变量保存状态,方便使用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    state = PENDING
    result = undefined
    constructor(func) {
        const resolve = (result) => {
            if (this.state == PENDING) {
                this.state = FULFILLED
                this.result = result
            }
        }

        const reject = (result) => {
            if (this.state == PENDING) {
                this.state = REJECTED
                this.result = result
            }
        }

        func(resolve, reject)
    }
    // 添加实例方法
    then(onFulfilled, onRejected) {
        // 参数判断  如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),它只是简单地将兑现值向前传递。
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
        // 参数判断  如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; }),它会抛出它收到的拒绝原因。
        onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }

        // 执行成功回调or执行失败回调(状态实例化完成就立即调用了,所以可以执行返回结果--》异步暂时不考虑)
        if (this.state === FULFILLED) {
            onFulfilled(this.result)
        } else if (this.state === REJECTED) {
            onRejected(this.result)
        }

    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {

    // resolve('success')
    reject('error')
})
// p.then((result) => {
//     console.log('成功回调', result)
// }, err => {
//     console.log('失败回调', err);
// })
p.then((result) => {
    console.log('成功回调', result)
})

异步及多次调用

  1. 定义实例属性,添加#为类内部使用标识
  2. 如果then执行后状态为pending存储异步时成功回调与失败回调
  3. 定时器两秒后 resolve执行 取出成功回调函数放入成功原因

  4. 定时器两秒后 reject执行 取出失败回调函数放入失败原因

/**
 * then-异步及多次调用
 * 1. 定义实例属性
 * 2. 保存回调函数
 * 3. 调用成功回调
 * 4. 调用失败回调
 */

//通过变量保存状态,方便使用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    state = PENDING
    result = undefined
    // 定义实例属性 #外部不能访问 保存回调
    #handlers = []//[{onFulfilled,onRejected}...]
    constructor(func) {
        const resolve = (result) => {
            if (this.state == PENDING) {
                this.state = FULFILLED
                this.result = result
                // 3.定时器两秒后 resolve执行 取出成功回调函数放入成功原因
                this.#handlers.forEach(({ onFulfilled }) => {
                    onFulfilled(this.result)
                })
            }
        }

        const reject = (result) => {
            if (this.state == PENDING) {
                this.state = REJECTED
                this.result = result
                // 4.定时器两秒后 reject执行 取出失败回调函数放入失败原因
                this.#handlers.forEach(({ onRejected }) => {
                    onRejected(this.result)
                })
            }
        }

        func(resolve, reject)
    }

    then(onFulfilled, onRejected) {

        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x

        onRejected = typeof onRejected === 'function' ? onRejected : (x) => { throw x }

        if (this.state === FULFILLED) {
            onFulfilled(this.result)
        } else if (this.state === REJECTED) {
            onRejected(this.result)
        } else if (this.state === PENDING) {
            // 2. 代表状态还没有发生过改变,保存回调函数
            this.#handlers.push({
                onFulfilled, onRejected
            })
        }

    }
}


// 测试代码
const p = new MyPromise((resolve, reject) => {

    setTimeout(() => {
        // resolve('success')
        reject('error')
    }, 2000);
})
p.then((result) => {
    console.log('成功回调', result)
}, err => {
    console.log('失败回调', err);
})
p.then((result) => {
    console.log('成功回调', result)
})

异步任务--核心api

 * Vue Promise.then, MutationObserver,setImmediate,setTimeout

 * 我们选用 queueMicrotask MutationObserver setTimeout

  • Promise.then,手写promise 不考虑这个
  • queueMicrotask:node11,新式浏览器(不包括ie11)
  • MutationObserver node不支持 ie11支持
  • setImmediate:ie10,11支持 edge:(12-18)支持(不考虑)
  • setTimeout:node,浏览器全支持

Promise.then:

  • 兼容性: 几乎所有现代浏览器和Node.js都支持Promise。
  • 用法: Promise是一种用于处理异步操作的机制,通过.then()方法可以注册回调函数来处理异步任务的完成或失败。例如:
const myPromise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 操作成功 */) {
    resolve(result);
  } else {
    reject(error);
  }
});

myPromise.then(
  (result) => {
    // 处理成功的情况
  },
  (error) => {
    // 处理失败的情况
  }
);

queueMicrotask:

Window 或 Worker 接口的 queueMicrotask() 方法,将微任务加入队列以在控制返回浏览器的事件循环之前的安全时间执行。

微任务是一个简短的函数,它将在当前任务完成其工作后运行,并且在执行上下文的控制权返回到浏览器的事件循环之前没有其他代码等待运行时运行。

它让你的代码在运行时不会干扰任何可能具有更高优先级的代码的运行,但在浏览器重新获得对执行上下文的控制之前,这可能取决于你需要完成的工作。你可以在我们的微任务指南中了解更多关于如何使用微任务以及选择这样做的原因。

微任务的重要性在于它能够以特定顺序异步执行任务。查看在 JavaScript 中通过 queueMicrotask() 使用微任务的详情。

微任务对于需要执行最后阶段的任务或其他在渲染之前的任务的库和框架特别有用。

参数

当浏览器引擎确定可以安全调用你的代码时执行的 function。微任务(microtask)的执行顺序在所有进行中的任务(pending task)完成之后,在对浏览器的事件循环产生控制(yielding control to the browser's event loop)之前。

返回值

无 undefined

  • 兼容性: 支持新式浏览器,但不包括IE11。
  • 用法: queueMicrotask用于将微任务排入微任务队列中,通常在Promise处理中使用,以确保微任务在宏任务之后执行。示例:
queueMicrotask(() => {
  // 这里执行微任务
});

MutationObserver:

MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

构造函数

MutationObserver()

创建并返回一个新的 MutationObserver 它会在指定的 DOM 发生变化时被调用。

方法

disconnect()

阻止 MutationObserver 实例继续接收的通知,直到再次调用其 observe() 方法,该观察者对象包含的回调函数都不会再被调用。

observe()

配置 MutationObserver 在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知。

takeRecords()

从 MutationObserver 的通知队列中删除所有待处理的通知,并将它们返回到 MutationRecord 对象的新 Array 中。

  • 兼容性: 在大多数现代浏览器中支持,但Node.js不支持,而IE11也支持。
  • 用法: MutationObserver用于监视DOM树的变化,并在发生变化时触发回调函数。这通常用于监听DOM元素的变化。示例:
// 选择需要观察变动的节点
const targetNode = document.getElementById("some-id");

// 观察器的配置(需要观察什么变动)
const config = { attributes: true, childList: true, subtree: true };

// 当观察到变动时执行的回调函数
const callback = function (mutationsList, observer) {
  // Use traditional 'for loops' for IE 11
  for (let mutation of mutationsList) {
    if (mutation.type === "childList") {
      console.log("A child node has been added or removed.");
    } else if (mutation.type === "attributes") {
      console.log("The " + mutation.attributeName + " attribute was modified.");
    }
  }
};

// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);

// 以上述配置开始观察目标节点
observer.observe(targetNode, config);

// 之后,可停止观察
observer.disconnect();

setImmediate:

setImmediate参数设置:第一个参数是需要执行的方法,第二个参数到第n个参数是传入方法中的参数。

setImmediate表示立即执行,它是宏任务,回调函数会被放置到事件循环的check阶段。
在应用中如果大量的计算型任务,它是不适合放在主线程中执行的,因为计算任务会阻塞主线程,主线程一旦被阻塞,其他任务就需要等待,
可以通过setImmediate方法将任务放入事件循环中的check阶段,因为代码在这一个阶段执行不会阻塞主线程,也不会阻塞事件循环
 

  • 兼容性: 主要支持IE10和IE11,以及一些较旧版本的Edge浏览器。
  • 用法: setImmediate用于将函数排入宏任务队列,以便在当前任务完成后立即执行。示例:
function sleep(delay) {
  var start = new Date().getTime()
  while (new Date().getTime() - start < delay) {
    continue
  }
  console.log('ok')
}

console.log('start')
setImmediate(sleep, 2000)
console.log('end')

先打印出start,然后再打印end,最后等待2000ms后打印ok。 

setTimeout:

  • 兼容性: 在Node.js和几乎所有现代浏览器中都支持。
  • 用法: setTimeout用于在一定时间后将函数排入宏任务队列。它是处理异步操作的常用方法。示例:
setTimeout(() => {
  // 这里执行宏任务
}, 1000);

异步任务---函数封装

  •  1.定义函数
  •  2.调用核心api(queueMicrotask,MutationObserver,setTimeout)
  •  3.使用封装的函数

 在then方法中使用无论promse是啥状态都需要直接或者间接的执行回调函数

/**
 * 异步任务--函数封装
 * 1.定义函数
 * 2.调用核心api(queueMicrotask,MutationObserver,setTimeout)
 * 3.使用封装的函数
 */

//1.定义函数
function runAsyncTask(callback) {
  //  2.调用核心api(queueMicrotask,MutationObserver,setTimeout)
  if (typeof queueMicrotask === "function") {
    queueMicrotask(callback);
  } else if (typeof MutationObserver == "function") {
    const obs = new MutationObserver(callback);
    const divNode = document.createElement("div");
    obs.observe(divNode, { childList: true });
    divNode.innerHTML = "贾公子";
  } else {
    setTimeout(callback, 0);
  }
}

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  state = PENDING;
  result = undefined;
  #handlers = [];
  constructor(func) {
    const resolve = (result) => {
      if (this.state == PENDING) {
        this.state = FULFILLED;
        this.result = result;
        this.#handlers.forEach(({ onFulfilled }) => {
          onFulfilled(this.result);
        });
      }
    };

    const reject = (result) => {
      if (this.state == PENDING) {
        this.state = REJECTED;
        this.result = result;
        this.#handlers.forEach(({ onRejected }) => {
          onRejected(this.result);
        });
      }
    };

    func(resolve, reject);
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (x) => x;

    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (x) => {
            throw x;
          };
    // 3.使用封装的函数
    if (this.state === FULFILLED) {
      runAsyncTask(() => {
        onFulfilled(this.result);
      });
    } else if (this.state === REJECTED) {
      runAsyncTask(() => {
        onRejected(this.result);
      });
    } else if (this.state === PENDING) {
      this.#handlers.push({
        // 成功或者失败后调用 onFulfilled
        // onFulfilled 执行之后调用runAsyncTask(传入:promise传入的回调)
        //runAsyncTask内部执行了回调 onFulfilled
        onFulfilled: () => {
          runAsyncTask(() => {
            onFulfilled(this.result);
          });
        },
        onRejected: () => {
          runAsyncTask(() => {
            onRejected(this.result);
          });
        },
      });
    }
  }
}

// 测试代码
console.log("TOP");
const p = new MyPromise((resolve, reject) => {
  // resolve("success");
  reject("error");
});
p.then(
  (result) => {
    console.log("成功回调", result);
  },
  (err) => {
    console.log("失败回调", err);
  }
);
console.log("BOTTOM");

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

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

相关文章

虾皮台湾站点如何选品

在互联网时代&#xff0c;电商平台成为了越来越多人购物的首选。虾皮作为台湾地区最大的电商平台之一&#xff0c;为商家提供了良好的销售渠道。然而&#xff0c;在虾皮上选择适合的商品对于商家来说并不容易。本文将介绍如何通过虾皮选品工具-知虾来查看台湾地区各大类目的热销…

预包装食品备案与食品经营许可证两者的关系

在食品行业中&#xff0c;预包装食品备案和食品经营许可证是两个重要的概念。它们之间存在一定的关系&#xff0c;但又不完全相同。本文将详细介绍两者的定义、区别和联系。 一、预包装食品备案 预包装食品备案&#xff0c;是指对预包装食品的生产者或进口商进行备案登记的一种…

scapy No such device exists (No such device exists)

使用python编写一个小的网络程序时&#xff0c;程序如下&#xff1a; import scapy.all as scapydef scan(ip):arp_request ARP(pdstip)arp_request.show()broadcast scapy.Ether(dst "ff:ff:ff:ff:ff:ff")arq_request_broadcast broadcast/arp_requestanswered,…

5.什么是Spring的依赖注入(DI)?IOC和DI的区别是什么

很多人把IOC和DI说成一个东西&#xff0c;笼统来说的话是没有问题的&#xff0c;但是本质上还是有所区别的,希望大家能够严谨一点&#xff0c; IOC和DI是从不同的角度描述的同一件事&#xff0c;IOC是从容器的角度描述&#xff0c;而DI是从应用程序的角度来描述&#xff0c;也…

kernel32.dll丢失都有什么解决办法,帮助大家解决kernel32.dll丢失的问题

kernel32.dll丢失是电脑中常出现的情况&#xff0c;今天就想和大脚聊聊这个kernel32.dll 文件&#xff0c;这个文件它的功能是干什么的&#xff0c;如果电脑中kernel32.dll 丢失都有什么解决办法&#xff0c;帮助大家解决kernel32.dll丢失的问题&#xff0c;本篇文章给大家提供…

LINUX入门篇【7】--git提交指令以及代码调试工具gdb

前言&#xff1a; 我们今天来介绍一下我们工具篇的最后两个工具&#xff0c;即git提交指令以及代码调试工具gdb,再结合前面的知识点&#xff0c;我们就可以基本完成我们VS上的基本的功能&#xff1a;编写&#xff0c;调试&#xff0c;编译&#xff0c;执行程序的这些过程。 1…

SpringDoc基础配置和集成OAuth2登录认证教程

本期内容 学会通过注解和Java代码的方式添加SpringDoc配置。在swagger-ui提供的页面上提供OAuth2登录认证&#xff0c;在集成Security的情况下便捷获取access_token并在请求时按照OAuth2规范携带。 为什么集成OAuth2登录认证&#xff1f; 现在大部分教程是在swagger-ui页面添…

为什么要建设渲染私有云?

生活中&#xff0c;其实各行各业都离不开渲染技术。建筑行业需要进行场景的渲染&#xff0c;以展示设计方案的效果&#xff1b;工业设计需要进行产品的渲染&#xff0c;以展示产品的外观和设计特点&#xff1b;游戏开发需要进行大量的游戏场景渲染&#xff0c;以测试游戏的视觉…

App性能测试工具Soloπ(四)---性能测试

一、性能测试录制 前提&#xff1a;手机已连接电脑&#xff0c;并已开启可调试及获取各种权限点击性能测试&#xff0c;进入性能数据监控项 如需开启启动耗时计算&#xff0c;进入录屏设置无需修改默认项 勾选监测项后则点击开始按钮&#xff08;绿色小三角&#xff09;进行…

nginx 代理接口报404 问题排查

今天遇到一个nginx代理后端接口请求报404的问题&#xff0c;问题是这样的&#xff0c;后端由于服务器没有环境&#xff0c;但是需要和前端联调&#xff0c;于是采用cpolar内网穿透的方式&#xff0c;穿出来了。但是前端请求跨域&#xff0c;于是前端用nginx代理了一下后端接口&…

面试官:你能说说常见的前端加密方法吗?

给大家推荐一个实用面试题库 1、前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;web前端面试题库 前言 本篇文章略微介绍一下前端中常见的加密算法。前端中常见的加密算法主要形式包括——哈希函数&#xff0c;对称…

Node.js之http模块

http模块是什么&#xff1f; http 模块是 Node,js 官方提供的、用来创建 web 服务器的模块。通过 http 模块提供的 http.createServer() 方法&#xff0c;就能方便的把一台普通的电脑&#xff0c;变成一台Web 服务器&#xff0c;从而对外提供 Web 资源服务。 如果我们想在node…

Qt http

文章目录 前言1. 定义的接口2.connect信号槽3. get4. get 下载文件5. post 总结 前言 /* 1.请求报文&#xff1a; 请求报文是由客户端发送给服务器&#xff0c;用于请求特定资源或执行特定操作。它由以下几个部分组成&#xff1a; 请求行&#xff1a;描述了请求的方法、目标资源…

josef约瑟 闭锁继电器 LB-7DG 100V 50HZ 导轨安装

LB-7型闭锁继电器 闭锁继电器LB-7导轨安装 一、用途 LB-7型闭锁继电器(以下简称继电器)用于发电厂及变电所内高压母线带电时防止和接地刀闸。 二、结构和工作原理 1、继电器按整流式原理构成&#xff0c;该继电器由变压器、电阻器、整流桥、滤波电容、极化继电器及指示灯组…

关于漏洞:检测到目标SSL证书已过期【原理扫描】

这个漏洞是监听443端口的&#xff0c;如果我们是正式的网站且使用了https那么更新证书即可。 但是我的服务器上面几乎是个空服务器&#xff0c;谁会用443呢&#xff1f; 找不到谁用了那我就部署一个nginx&#xff0c;用nginx代理443&#xff0c;找个证书配一下呗。 然而当我…

学了这么久,你知道Python机器学习全流程是怎样的么?

万事开头难&#xff0c;首先Python机器学习整个流程的第一步就是学习Python这门编程语言的相关基础知识。 第一步&#xff1a;基本 Python 技能 如果要使用 Python 进行机器学习&#xff0c;拥有对 Python 有基础的理解非常关键。幸运的是&#xff0c;Python 是当前普遍使用的…

【Linux】Linux下的基础IO

❤️前言 大家好&#xff01;今天这篇博客和大家聊一聊关于Linux下的基础IO。 正文 在阅读本篇博客之前&#xff0c;请大家先回顾一下C语言文件操作的一些方法&#xff0c;这里可以看看我之前记录的一些内容&#xff1a; 【C语言】C语言成长之路之文件操作_MO_lion的博客-CSD…

移动端获取ua头的值

目录&#xff1a; 1、检测地址2、测试结果 1、检测地址 http://www.ip138.com/useragent/ 2、测试结果 成功的拿到了ua头的值了&#xff0c;亲测可行&#xff01;&#xff01;&#xff01;

红海营销时代,内容占位的出海品牌更有机会营销占位

#01 品牌出海&#xff1a;内容占位就是品牌营销占位 红海营销时代&#xff0c;内容信息充斥着用户周边。无论线上还是线下&#xff0c;生活工作、休闲娱乐等不同场景内&#xff0c;广告信息均无孔不入。对于用户来说&#xff0c;能记住的品牌或者商品往往寥寥无几。 占位营销…

Mysql超详细安装配置教程(保姆级)

目录 一、下载Mysql 二、安装Mysql 三、配置Mysql 四、连接Mysql 五、部分疑难问题 一、下载Mysql 从官网下载MySQL&#xff0c;这里我选用的是Mysql8.0.34版本 二、安装Mysql 下载完成后直接双击进行安装&#xff0c;打开后的页面如下所示&#xff1a; “Developer Defa…