promise链式调用_这一次,彻底弄懂 Promise

Promise 必须为以下三种状态之一:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。一旦Promise 被 resolve 或 reject,不能再迁移至其他任何状态(即状态 immutable)。

基本过程:

  1. 初始化 Promise 状态(pending)
  2. 执行 then(..) 注册回调处理数组(then 方法可被同一个 promise 调用多次)
  3. 立即执行 Promise 中传入的 fn 函数,将Promise 内部 resolve、reject 函数作为参数传递给 fn ,按事件机制时机处理
  4. Promise里的关键是要保证,then方法传入的参数 onFulfilled 和 onRejected,必须在then方法被调用的那一轮事件循环之后的新执行栈中执行。

真正的链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise.

链式调用

先从 Promise 执行结果看一下,有如下一段代码:

 new Promise((resolve, reject) => { setTimeout(() => { resolve({ test: 1 }) resolve({ test: 2 }) reject({ test: 2 }) }, 1000) }).then((data) => { console.log('result1', data) },(data1)=>{ console.log('result2',data1) }).then((data) => { console.log('result3', data) }) //result1 { test: 1 } //result3 undefined复制代码

显然这里输出了不同的 data。由此可以看出几点:

  1. 可进行链式调用,且每次 then 返回了新的 Promise(2次打印结果不一致,如果是同一个实例,打印结果应该一致。
  2. 只输出第一次 resolve 的内容,reject 的内容没有输出,即 Promise 是有状态且状态只可以由pending -> fulfilled或 pending-> rejected,是不可逆的。
  3. then 中返回了新的 Promise,但是then中注册的回调仍然是属于上一个 Promise 的。

基于以上几点,我们先写个基于 PromiseA+ 规范的只含 resolve 方法的 Promise 模型:

 function Promise(fn){  let state = 'pending'; let value = null; const callbacks = []; this.then = function (onFulfilled){ return new Promise((resolve, reject)=>{ handle({ //桥梁,将新 Promise 的 resolve 方法,放到前一个 promise 的回调对象中 onFulfilled,  resolve }) }) } function handle(callback){ if(state === 'pending'){ callbacks.push(callback) return; }  if(state === 'fulfilled'){ if(!callback.onFulfilled){ callback.resolve(value) return; } const ret = callback.onFulfilled(value) //处理回调 callback.resolve(ret) //处理下一个 promise 的resolve } } function resolve(newValue){ const fn = ()=>{ if(state !== 'pending')return state = 'fulfilled'; value = newValue handelCb() }  setTimeout(fn,0) //基于 PromiseA+ 规范 }  function handelCb(){ while(callbacks.length) { const fulfiledFn = callbacks.shift(); handle(fulfiledFn); }; }  fn(resolve) }复制代码

这个模型简单易懂,这里最关键的点就是在 then 中新创建的 Promise,它的状态变为 fulfilled 的节点是在上一个 Promise的回调执行完毕的时候。也就是说当一个 Promise 的状态被 fulfilled 之后,会执行其回调函数,而回调函数返回的结果会被当作 value,返回给下一个 Promise(也就是then 中产生的 Promise),同时下一个 Promise的状态也会被改变(执行 resolve 或 reject),然后再去执行其回调,以此类推下去...链式调用的效应就出来了。

但是如果仅仅是例子中的情况,我们可以这样写:

 new Promise((resolve, reject) => { setTimeout(() => { resolve({ test: 1 }) }, 1000) }).then((data) => { console.log('result1', data) //dosomething console.log('result3') }) //result1 { test: 1 } //result3复制代码

实际上,我们常用的链式调用,是用在异步回调中,以解决"回调地狱"的问题。如下例子:

new Promise((resolve, reject) => { setTimeout(() => { resolve({ test: 1 }) }, 1000)}).then((data) => { console.log('result1', data) //dosomething return test()}).then((data) => { console.log('result2', data)})function test(id) { return new Promise(((resolve) => { setTimeout(() => { resolve({ test: 2 }) }, 5000) }))}//基于第一个 Promise 模型,执行后的输出//result1 { test: 1 }//result2 Promise {then: ƒ}复制代码

用上面的 Promise 模型,得到的结果显然不是我们想要的。认真看上面的模型,执行 callback.resolve 时,传入的参数是 callback.onFulfilled 执行完成的返回,显然这个测试例子返回的就是一个 Promise,而我们的 Promise 模型中的 resolve 方法并没有特殊处理。那么我们将 resolve 改一下:

 function Promise(fn){  ... function resolve(newValue){ const fn = ()=>{ if(state !== 'pending')return if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){ const {then} = newValue if(typeof then === 'function'){ // newValue 为新产生的 Promise,此时resolve为上个 promise 的resolve //相当于调用了新产生 Promise 的then方法,注入了上个 promise 的resolve 为其回调 then.call(newValue,resolve) return } } state = 'fulfilled'; value = newValue handelCb() }  setTimeout(fn,0) } ... }复制代码

用这个模型,再测试我们的例子,就得到了正确的结果:

 new Promise((resolve, reject) => { setTimeout(() => { resolve({ test: 1 }) }, 1000) }).then((data) => { console.log('result1', data) //dosomething return test() }).then((data) => { console.log('result2', data) }) function test(id) { return new Promise(((resolve, reject) => { setTimeout(() => { resolve({ test: 2 }) }, 5000) })) } //result1 { test: 1 } //result2 { test: 2 }复制代码

显然,新增的逻辑就是针对 resolve 入参为 Promise 的时候的处理。我们观察一下 test 里面创建的 Promise,它是没有调用 then方法的。从上面的分析我们已经知道 Promise 的回调函数就是通过调用其 then 方法注册的,因此 test 里面创建的 Promise 其回调函数为空。

显然如果没有回调函数,执行 resolve 的时候,是没办法链式下去的。因此,我们需要主动为其注入回调函数。

我们只要把第一个 then 中产生的 Promise 的 resolve 函数的执行,延迟到 test 里面的 Promise 的状态为 onFulfilled 的时候再执行,那么链式就可以继续了。所以,当 resolve 入参为 Promise 的时候,调用其 then 方法为其注入回调函数,而注入的是前一个 Promise 的 resolve 方法,所以要用 call 来绑定 this 的指向。

基于新的 Promise 模型,上面的执行过程产生的 Promise 实例及其回调函数,可以用看下表:

Promise callback P1 [{onFulfilled:c1(第一个then中的fn),resolve:p2resolve}] P2 (P1 调用 then 时产生) [{onFulfilled:c2(第二个then中的fn),resolve:p3resolve}] P3 (P2 调用 then 时产生) [] P4 (执行c1中产生[调用 test ]) [{onFulfilled:p2resolve,resolve:p5resolve}] P5 (调用p2resolve 时,进入 then.call 逻辑中产生) [] 有了这个表格,我们就可以清晰知道各个实例中 callback 执行的顺序是:

c1 -> p2resolve -> c2 -> p3resolve -> [] -> p5resolve -> []

以上就是链式调用的原理了。

reject

下面我们再来补全 reject 的逻辑。只需要在注册回调、状态改变时加上 reject 的逻辑即可。

完整代码如下:

 function Promise(fn){  let state = 'pending'; let value = null; const callbacks = []; this.then = function (onFulfilled,onRejected){ return new Promise((resolve, reject)=>{ handle({ onFulfilled,  onRejected, resolve,  reject }) }) } function handle(callback){ if(state === 'pending'){ callbacks.push(callback) return; }  const cb = state === 'fulfilled' ? callback.onFulfilled:callback.onRejected; const next = state === 'fulfilled'? callback.resolve:callback.reject; if(!cb){ next(value) return; } const ret = cb(value) next(ret) } function resolve(newValue){ const fn = ()=>{ if(state !== 'pending')return if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){ const {then} = newValue if(typeof then === 'function'){ // newValue 为新产生的 Promise,此时resolve为上个 promise 的resolve //相当于调用了新产生 Promise 的then方法,注入了上个 promise 的resolve 为其回调 then.call(newValue,resolve, reject) return } } state = 'fulfilled'; value = newValue handelCb() }  setTimeout(fn,0) } function reject(error){ const fn = ()=>{ if(state !== 'pending')return if(error && (typeof error === 'object' || typeof error === 'function')){ const {then} = error if(typeof then === 'function'){ then.call(error,resolve, reject) return } } state = 'rejected'; value = error handelCb() } setTimeout(fn,0) } function handelCb(){ while(callbacks.length) { const fn = callbacks.shift(); handle(fn); }; } fn(resolve, reject) }复制代码

异常处理

异常通常是指在执行成功/失败回调时代码出错产生的错误,对于这类异常,我们使用 try-catch 来捕获错误,并将 Promise 设为 rejected 状态即可。

handle代码改造如下:

 function handle(callback){ if(state === 'pending'){ callbacks.push(callback) return; }  const cb = state === 'fulfilled' ? callback.onFulfilled:callback.onRejected; const next = state === 'fulfilled'? callback.resolve:callback.reject; if(!cb){ next(value) return; } try { const ret = cb(value) next(ret) } catch (e) { callback.reject(e); }  }复制代码

我们实际使用时,常习惯注册 catch 方法来处理错误,例:

 new Promise((resolve, reject) => { setTimeout(() => { resolve({ test: 1 }) }, 1000) }).then((data) => { console.log('result1', data) //dosomething return test() }).catch((ex) => { console.log('error', ex) })复制代码

实际上,错误也好,异常也罢,最终都是通过reject实现的。也就是说可以通过 then 中的错误回调来处理。所以我们可以增加这样的一个 catch 方法:

 function Promise(fn){  ... this.then = function (onFulfilled,onRejected){ return new Promise((resolve, reject)=>{ handle({ onFulfilled,  onRejected, resolve,  reject }) }) } this.catch = function (onError){ this.then(null,onError) } ... }复制代码

Finally方法

在实际应用的时候,我们很容易会碰到这样的场景,不管Promise最后的状态如何,都要执行一些最后的操作。我们把这些操作放到 finally 中,也就是说 finally 注册的函数是与 Promise 的状态无关的,不依赖 Promise 的执行结果。所以我们可以这样写 finally 的逻辑:

 function Promise(fn){  ... this.catch = function (onError){ this.then(null,onError) } this.finally = function (onDone){ this.then(onDone,onDone) } ... }复制代码

resolve 方法和 reject 方法

实际应用中,我们可以使用 Promise.resolve 和 Promise.reject 方法,用于将于将非 Promise 实例包装为 Promise 实例。如下例子:

Promise.resolve({name:'winty'})Promise.reject({name:'winty'})// 等价于new Promise(resolve => resolve({name:'winty'}))new Promise((resolve,reject) => reject({name:'winty'}))复制代码

这些情况下,Promise.resolve 的入参可能有以下几种情况:

  • 无参数 [直接返回一个resolved状态的 Promise 对象]
  • 普通数据对象 [直接返回一个resolved状态的 Promise 对象]
  • 一个Promise实例 [直接返回当前实例]
  • 一个thenable对象(thenable对象指的是具有then方法的对象) [转为 Promise 对象,并立即执行thenable对象的then方法。]

基于以上几点,我们可以实现一个 Promise.resolve 方法如下:

 function Promise(fn){  ... this.resolve = function (value){ if (value && value instanceof Promise) { return value; } else if (value && typeof value === 'object' && typeof value.then === 'function'){ let then = value.then; return new Promise(resolve => { then(resolve); }); } else if (value) { return new Promise(resolve => resolve(value)); } else { return new Promise(resolve => resolve()); } } ... }复制代码

Promise.reject与Promise.resolve类似,区别在于Promise.reject始终返回一个状态的rejected的Promise实例,而Promise.resolve的参数如果是一个Promise实例的话,返回的是参数对应的Promise实例,所以状态不一 定。 因此,reject 的实现就简单多了,如下:

 function Promise(fn){  ... this.reject = function (value){ return new Promise(function(resolve, reject) {reject(value);}); } ... }复制代码

Promise.all

入参是一个 Promise 的实例数组,然后注册一个 then 方法,然后是数组中的 Promise 实例的状态都转为 fulfilled 之后则执行 then 方法。这里主要就是一个计数逻辑,每当一个 Promise 的状态变为 fulfilled 之后就保存该实例返回的数据,然后将计数减一,当计数器变为 0 时,代表数组中所有 Promise 实例都执行完毕。

 function Promise(fn){  ... this.all = function (arr){ var args = Array.prototype.slice.call(arr); return new Promise(function(resolve, reject) { if(args.length === 0) return resolve([]); var remaining = args.length; function res(i, val) { try { if(val && (typeof val === 'object' || typeof val === 'function')) { var then = val.then; if(typeof then === 'function') { then.call(val, function(val) { res(i, val); }, reject); return; } } args[i] = val; if(--remaining === 0) { resolve(args); } } catch(ex) { reject(ex); } } for(var i = 0; i < args.length; i++) { res(i, args[i]); } }); } ... }复制代码

Promise.race

有了 Promise.all 的理解,Promise.race 理解起来就更容易了。它的入参也是一个 Promise 实例数组,然后其 then 注册的回调方法是数组中的某一个 Promise 的状态变为 fulfilled 的时候就执行。因为 Promise 的状态只能改变一次,那么我们只需要把 Promise.race 中产生的 Promise 对象的 resolve 方法,注入到数组中的每一个 Promise 实例中的回调函数中即可。

function Promise(fn){  ... this.race = function(values) { return new Promise(function(resolve, reject) { for(var i = 0, len = values.length; i < len; i++) { values[i].then(resolve, reject); } }); } ... } 复制代码

总结

Promise 源码不过几百行,我们可以从执行结果出发,分析每一步的执行过程,然后思考其作用即可。其中最关键的点就是要理解 then 函数是负责注册回调的,真正的执行是在 Promise 的状态被改变之后。而当 resolve 的入参是一个 Promise 时,要想链式调用起来,就必须调用其 then 方法(then.call),将上一个 Promise 的 resolve 方法注入其回调数组中。

补充说明

虽然 then 普遍认为是微任务。但是浏览器没办法模拟微任务,目前要么用 setImmediate ,这个也是宏任务,且不兼容的情况下还是用 setTimeout 打底的。还有,promise 的 polyfill (es6-promise) 里用的也是 setTimeout。因此这里就直接用 setTimeout,以宏任务来代替微任务了。

参考资料

  • PromiseA+规范
  • Promise 实现原理精解
  • 30分钟,让你彻底明白Promise原理

完整 Promise 模型

function Promise(fn) { let state = 'pending' let value = null const callbacks = [] this.then = function (onFulfilled, onRejected) { return new Promise((resolve, reject) => { handle({ onFulfilled, onRejected, resolve, reject, }) }) } this.catch = function (onError) { this.then(null, onError) } this.finally = function (onDone) { this.then(onDone, onError) } this.resolve = function (value) { if (value && value instanceof Promise) { return value } if (value && typeof value === 'object' && typeof value.then === 'function') { const { then } = value return new Promise((resolve) => { then(resolve) }) } if (value) { return new Promise(resolve => resolve(value)) } return new Promise(resolve => resolve()) } this.reject = function (value) { return new Promise(((resolve, reject) => { reject(value) })) } this.all = function (arr) { const args = Array.prototype.slice.call(arr) return new Promise(((resolve, reject) => { if (args.length === 0) return resolve([]) let remaining = args.length function res(i, val) { try { if (val && (typeof val === 'object' || typeof val === 'function')) { const { then } = val if (typeof then === 'function') { then.call(val, (val) => { res(i, val) }, reject) return } } args[i] = val if (--remaining === 0) { resolve(args) } } catch (ex) { reject(ex) } } for (let i = 0; i < args.length; i++) { res(i, args[i]) } })) } this.race = function (values) { return new Promise(((resolve, reject) => { for (let i = 0, len = values.length; i < len; i++) { values[i].then(resolve, reject) } })) } function handle(callback) { if (state === 'pending') { callbacks.push(callback) return } const cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected const next = state === 'fulfilled' ? callback.resolve : callback.reject if (!cb) { next(value) return } try { const ret = cb(value) next(ret) } catch (e) { callback.reject(e) } } function resolve(newValue) { const fn = () => { if (state !== 'pending') return if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { const { then } = newValue if (typeof then === 'function') { // newValue 为新产生的 Promise,此时resolve为上个 promise 的resolve // 相当于调用了新产生 Promise 的then方法,注入了上个 promise 的resolve 为其回调 then.call(newValue, resolve, reject) return } } state = 'fulfilled' value = newValue handelCb() } setTimeout(fn, 0) } function reject(error) { const fn = () => { if (state !== 'pending') return if (error && (typeof error === 'object' || typeof error === 'function')) { const { then } = error if (typeof then === 'function') { then.call(error, resolve, reject) return } } state = 'rejected' value = error handelCb() } setTimeout(fn, 0) } function handelCb() { while (callbacks.length) { const fn = callbacks.shift() handle(fn) } } fn(resolve, reject)}
7bb332ddb75652459a01980fdd1b0e49.png

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

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

相关文章

visual studio 判断dropdownlist选的是什么_心理测试:五个小蓝人,你选哪个?测你是不是一个容易追求的人...

下面这张图片里&#xff0c;有五个小蓝人&#xff0c;你觉得自己会是里面的哪一个&#xff1f;A. 站在家里的窗户边B. 站在河边C. 坐在屋顶D. 站在树上E. 骑着鸟飞在空中测试结果选A的你容易追求指数20%。你是一个温柔细腻的人。在别人的眼里&#xff0c;你是一个很贴心的人。在…

java中为何输出框会无限输出,MyBatis启动时控制台无限输出日志的原因及解决办法...

你是否遇到过下面的情况&#xff0c;控制台无限的输出下面的日志&#xff1a;Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl adapter.Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl adapter.Logging initiali…

基于注解SpringAOP,AfterReturning,Before,Around__springboot工程 @Around 简单的使用__SpringBoot:AOP 自定义注解实现日志管理

基于注解SpringAOP&#xff0c;AfterReturning&#xff0c;Before&#xff0c;Around AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff0c;即面向切面编程&#xff08;也叫面向方面编程&#xff0c;面向方法编程&#xff09;。其主要作用是&#xff0c;在不修…

流浪地球开机动画包zip_【文娱热点】流浪地球2定档2023大年初一;迪士尼计划裁员32000人...

剧集、综艺任嘉伦、白鹿《长安如故》开机11月26日&#xff0c;根据小说《一生一世美人骨》古代篇改编的剧集《长安如故》开机&#xff0c;两位主演任嘉伦和白鹿继现代篇《一生一世》之后再演古代篇&#xff0c;俩人穿着棉服、梳着古装发髻现身开机仪式&#xff0c;心情非常好。…

matlab读气象数据,中国气象数据网

“中国气象科学数据共享服务网”的气象卫星资料与国内其他气象卫星资料发布平台的最大不同之处&#xff0c;在于卫星数据资源内容不同且时间序列相当完整。而且&#xff0c;(1)数据获取更便捷。在线获取数据无需等待邮件通知&#xff0c;无数据下载量限制。共享卫星资源是公益性…

spring中自定义注解(annotation)与AOP中获取注解___使用aspectj的@Around注解实现用户操作和操作结果日志

spring中自定义注解(annotation)与AOP中获取注解 一、自定义注解(annotation) 自定义注解的作用&#xff1a;在反射中获取注解&#xff0c;以取得注解修饰的类、方法或属性的相关解释。 package me.lichunlong.spring.annotation;import java.lang.annotation.Documented; …

python 编译器pyc_有没有办法知道哪个Python版本.pyc文件被编译?

Is there any way to know by which Python version the .pyc file was compiled? 解决方案 You can get the magic number of your Python as follows: $ python -V Python 2.6.2 # python >>> import imp >>> imp.get_magic().encode(hex) d1f20d0a To ge…

Spring AOP——Spring 中面向切面编程

前面两篇文章记录了 Spring IOC 的相关知识&#xff0c;本文记录 Spring 中的另一特性 AOP 相关知识。 部分参考资料&#xff1a; 《Spring实战&#xff08;第4版&#xff09;》 《轻量级 JavaEE 企业应用实战&#xff08;第四版&#xff09;》 Spring 官方文档 W3CSchool Spri…

python getchar,Linux C编程学习:getchar()和getch()

getchar函数名: getchar功 能: 从stdin流中读字符用 法: int getchar(void);注解&#xff1a;getchar有一个int型的返回值&#xff0c;当程序调用getchar时程序就等着用户按键&#xff0c;用户输入的字符被存放在键盘缓冲区中直到用户按回车为止(回车字符也放在缓冲区中)。当用…

python 折线图中文乱码_彻底解决 Python画图中文乱码问题--Pyplotz组件

1 源起 自从开始学习Python&#xff0c;就非常喜欢用来画图。一直没有需求画要中文显示信息的图&#xff0c;所以没有配置Python中文的环境。由于昨天就需要画几十个形式相同&#xff0c;只是数据不同的图&#xff0c;并且需要显示中文信息。如果用Excel画图会很浪费时间&#…

SpringBoot的AOP是默认开启的,不需要加注解@EnableAspectJAutoProxy____听说SpringAOP 有坑?那就来踩一踩

Aspect Component public class CustomerServiceInterceptor {Before("execution(public * org.example.aop.demo..*.*(..))")public void doBefore() {System.out.println("do some important things before...");} }另外SpringBoot默认是cglib动态代理&a…

mysql 开启远程访问_QxOrm 访问 MySQL

在前面的 QxOrm 章节中&#xff0c;我们已经介绍了对本地数据库的操作&#xff0c;现在是时候介绍对远程数据库的访问了&#xff0c;那么就以最常用的 MySQL 为例吧&#xff01;在开始之前&#xff0c;首先要安装 MySQL。如果条件允许&#xff0c;建议将其安装在 Linux 系统上&…

当泛型遇到重载

当泛型遇到了重载&#xff0c;好戏&#xff0c;就发生了。 请看下面代码&#xff1a; 问题&#xff1a;代码能正确编译吗&#xff1f; 这个题目是一个考察泛型的题目。java里面&#xff0c;泛型实际上是“伪泛型”&#xff0c;并不像C#那样是实际上的泛型。 IDE会提示我们下…

redis查询所有key命令_三歪推荐:Redis常见的面试题

本文公众号来源&#xff1a;科技缪缪作者&#xff1a;科技缪缪本文已收录至我的GitHub说说Redis基本数据类型有哪些吧字符串&#xff1a;redis没有直接使用C语言传统的字符串表示&#xff0c;而是自己实现的叫做简单动态字符串SDS的抽象类型。C语言的字符串不记录自身的长度信息…

springboot系列——redisTemplate和stringRedisTemplate对比、redisTemplate几种序列化方式比较

文章目录一、redisTemplate和stringRedisTemplate对比1、StringRedisTemplate2、RedisTemplate二、redisTemplate序列化方式比较1、性能测试对比2、性能总结3、方案一、考虑效率和可读性&#xff0c;牺牲部分空间4、方案二、空间敏感&#xff0c;忽略可读性和效率影响5、使用示…

mysql查询默认排序规则_深究 mysql 默认排序, order by 的顺序【收藏】

mysql 语句中如果没有使用 order by 来排序&#xff0c;通常会用 主键正序排列&#xff0c;但是有的时候不是这样&#xff0c;来看一个实例。实例群友问&#xff1a;请教一个问题&#xff0c;mysql 默认排序问题&#xff0c;当sql 语句 的排序没有指定 主键&#xff08;id&…

Spring Boot jackson配置使用详解

Spring Boot系列-json框架jackson配置详解 T1 - 前言 目前Java最常见的3中JSON操作框架分别为Gson、Jackson、FastJson&#xff0c;该篇文章主要讲解jackson在SpringBoot环境中各配置项的具体作用。 T2 - 环境依赖 jackson是spring-boot的web/webflux框架默认依赖的json库&…

频率统计表用c语言_空间矢量脉宽调制建模与仿真(基于C语言的SIMULINK仿真模型 | 基于SVPWM模块的仿真)...

文末有仿真模型下载方式1.1 基于C语言的SIMULINK仿真模型使用C语言在MATLAB/SIMULINK中仿真&#xff0c;需要借助s-function builder模块实现。七段式SVPWM仿真模型如图1-1所示。仿真解算器&#xff08;Solver&#xff09;选择变步长&#xff08;Variable-step&#xff09;、od…

php基本语法 格式,PHP 基本语法格式

PHP 基本语法格式标准代码如下:复制代码 代码如下:...?>短标签模式(此模式需要修改PHP配置&#xff0c;让PHP支持短标签模式)&#xff1a;复制代码 代码如下:...?>注释&#xff1a;复制代码 代码如下:/* ...*///#时间&#xff1a; 2009-12-14Abs: 取得绝对值. Acos: 取…

linux 服务器启用端口,linux服务器放行端口

一、默认使用iptables的系统(例如centos6)1、关闭所有的 INPUT FORWARD OUTPUT 只对某些端口开放。下面是命令实现&#xff1a;iptables -P INPUT DROPiptables -P FORWARD DROPiptables -P OUTPUT DROP再用命令iptables -L -n查看 是否设置好&#xff0c; 好看到全部 DROP 了这…