es6---Promise
promise是什么?
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。它最早由社区提出并实现,ES6将其写进了语言标准,统一了用法,并原生提供了Promise对象。
1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列
为什么会有promise?
为了避免界面冻结(任务)
同步:假设你去了一家饭店,找个位置,叫来服务员,这个时候服务员对你说,对不起我是“同步”服务员,我要服务完这张桌子才能招呼你。那桌客人明明已经吃上了,你只是想要个菜单,这么小的动作,服务员却要你等到别人的一个大动作完成之后,才能再来招呼你,这个便是同步的问题:也就是“顺序交付的工作1234,必须按照1234的顺序完成”。
异步:则是将耗时很长的A交付的工作交给系统之后,就去继续做B交付的工作,。等到系统完成了前面的工作之后,再通过回调或者事件,继续做A剩下的工作。
AB工作的完成顺序,和交付他们的时间顺序无关,所以叫“异步”。
异步操作的常见语法
1.事件监听
document.getElementById('#start').addEventListener('click', start, false);
function start() {// 响应事件,进行相应的操作
}
// jquery on 监听
$('#start').on('click', start)
2.回调
// 比较常见的有ajax
$.ajax('https://www.baidu.com/', {success (res) {// 这里可以监听res返回的数据做回调逻辑的处理}
})// 或者在页面加载完毕后回调
$(function() {// 页面结构加载完成,做回调逻辑处理
})
有了nodeJS之后...对异步的依赖进一步加剧了
大家都知道在nodeJS出来之前PHP、Java、python等后台语言已经很成熟了,nodejs要想能够有自己的一片天,那就得拿出点自己的绝活:
无阻塞高并发,是nodeJS的招牌,要达到无阻塞高并发异步是其基本保障
举例:查询数据从数据库,PHP第一个任务查询数据,后面有了新任务,那么后面任务会被挂起排队;而nodeJS是第一个任务挂起交给数据库去跑,然后去接待第二个任务交给对应的系统组件去处理挂起,接着去接待第三个任务...那这样子的处理必然要依赖于异步操作
异步回调的问题:
- 之前处理异步是通过纯粹的回调函数的形式进行处理
- 很容易进入到回调地狱中,剥夺了函数 return 的能力
- 问题可以解决,但是难以读懂,维护困难
- 稍有不慎就会踏入回调地狱 - 嵌套层次深,不好维护
地狱回调:
一般情况我们一次性调用API就可以完成请求。
有些情况需要多次调用服务器API,就会形成一个链式调用,比如为了完成一个功能,我们需要调用API1、API2、API3,依次按照顺序进行调用,这个时候就会出现回调地狱的问题
如何创建promise对象
创建Promise对象有两种方式:
方式一 通过Promise构造函数
- promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
- 并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
- 代码风格,容易理解,便于维护
- 多个异步等待合并便于解决
new Promise(function (resolve, reject) {// 一段耗时的异步操作resolve('成功') // 数据处理完成// reject('失败') // 数据处理出错}
).then((res) => {console.log(res)}, // 成功(err) => {console.log(err)} // 失败
)
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由JavaScript引擎提供,不用自己部署。
- resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。 - promise对象的状态不受外界影响 (3种状态):
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;promise状态一经改变,不会再变。 - 一旦状态改变就不会再变 (两种状态改变:成功或失败):
从pending变为fulfilled(成功)
从pending变为rejected(失败)
这两种情况只要发生,状态就凝固了,不会再变了。
对于第一种方式,需要手动判断成功还是失败,比如你获取用户信息:
// 定义一个函数,用于获取用户信息
function getUserInfo(userId) {// 使用Promise手动管理异步操作return new Promise(function(resolve, reject) {// 假设获取用户信息是一个异步操作,需要一定时间setTimeout(function() {// 假设获取到了用户信息let user = { id: userId, name: '张三', age: 18 };// 判断用户是否存在if (user) {// 如果存在,使用resolve方法将Promise状态变为成功态resolve(user);} else {// 如果不存在,使用reject方法将Promise状态变为失败态reject('用户不存在');}}, 1000);});
}// 调用getUserInfo函数获取用户信息
getUserInfo('001').then(function(user) {// 如果获取用户信息成功,将打印用户信息console.log(user);}).catch(function(error) {// 如果获取用户信息失败,将打印错误信息console.log(error);});
在该例子中,使用Promise手动管理异步操作。在getUserInfo函数中创建了一个Promise对象,将异步操作封装在其中,当异步操作执行成功时,使用resolve方法将Promise状态变为成功态,并传递用户信息,当异步操作执行失败时,使用reject方法将Promise状态变为失败态,并传递错误信息。使用then方法和catch方法分别处理Promise的状态变化,如果Promise状态变为成功态,将打印用户信息,如果Promise状态变为失败态,将打印错误信息。
方式二 通过静态方法创建一个Promise对象
也称为Promise的自动化管理方式。比如,Promise.resolve()可以创建一个状态为成功的Promise对象,Promise.reject()可以创建一个状态为失败的Promise对象。
// 第二种方式,自动管理
let promise = Promise.resolve('successful');
let promise = Promise.reject('failed');
关于第二种方式,也给一个例子:
// 模拟一个异步操作函数
function asyncFunction() {return new Promise((resolve, reject) => {// 模拟一个异步操作,2秒钟后将结果返回setTimeout(() => {resolve('success');}, 2000);});
}// 返回一个已解决的Promise对象,并使用函数返回值作为解决结果
Promise.resolve(asyncFunction()).then((value) => {console.log('异步操作执行成功', value);// 在这里处理异步操作执行成功的情况}).catch((error) => {console.error('异步操作执行失败', error);// 在这里处理异步操作执行失败的情况});
在这个例子中,我们定义了一个asyncFunction()函数,该函数返回一个Promise对象,在Promise对象的构造函数中使用setTimeout模拟了一个异步操作。然后我们使用Promise.resolve()方法将异步操作函数的返回值转换成一个自动管理状态的Promise对象。最后,我们在使用Promise.resolve()方法返回的Promise对象上使用.then()方法和.catch()方法处理异步操作成功或失败的情况。
使用Promise.resolve()方法的好处在于,如果被传入的参数本来就是一个Promise对象,那么直接返回这个Promise对象,如果不是Promise对象,会自动转换成Promise对象,方便在异步操作逻辑中使用。
无论是哪种方式,创建的Promise对象都将具有pending(等待态)状态,调用resolve或reject方法可以改变其状态,并传递相应的值或错误。
最简单示例:
new Promise(resolve => {setTimeout(() => {resolve('hello')}, 2000)
}).then(res => {console.log(res)
})
分两次,顺序执行
new Promise((resolve, reject) => {setTimeout(() => {resolve('hello')// 1参数val = 'hello'}, 1000)}).then(val => {console.log(val);return new Promise((resolve, reject) => {setTimeout(() => {resolve('world')}, 1000)})}).then(val => {console.log(val);// 2参数val = 'world'})
promise完成后then()
let pro = new Promise((resolve, reject) => {setTimeout(() => {resolve('hello world')// 1参数val = 'hello'}, 1000)})setTimeout(() => {pro.then(val => {console.log(val); // 参数val = 'hello world'}, 1000)})console.log(pro.then(val => {}) instanceof Promise); // true
结论:promise作为队列最为重要的特性,我们在任何一个地方生成了一个promise队列之后,我们可以把他作为一个变量传递到其他地方。
.then()
1、接收两个函数作为参数,分别代表fulfilled(成功)和rejected(失败)
2、.then()返回一个新的Promise实例,所以它可以链式调用
3、当前面的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行
4、状态响应函数可以返回新的promise,或其他值,不返回值也可以我们可以认为它返回了一个null;
5、如果返回新的promise,那么下一级.then()会在新的promise状态改变之后执行
6、如果返回其他任何值,则会立即执行下一级.then()
.then()里面有.then()的情况
1、因为.then()返回的还是Promise实例
2、会等里面的then()执行完,再执行外面的
对于我们来说,此时最好将其展开,也是一样的结果,而且会更好读:
执行顺序
接下来我们探究一下它的执行顺序,看以下代码:
let promise = new Promise(function(resolve, reject){console.log("AAA");resolve()
});
promise.then(() => console.log("BBB"));
console.log("CCC")// AAA
// CCC
// BBB
执行后,我们发现输出顺序总是 AAA -> CCC -> BBB
。表明,在Promise新建后会立即执行,所以首先输出 AAA
。然后,then方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行,所以BBB 最后输出
。
与定时器混用
首先看一个实例:
let promise = new Promise(function(resolve, reject){console.log("1");resolve();
});
setTimeout(()=>console.log("2"), 0);
promise.then(() => console.log("3"));
console.log("4");// 1
// 4
// 3
// 2
可以看到,结果输出顺序总是:1 -> 4 -> 3 -> 2
。1与4的顺序不必再说,而2与3先输出Promise的then,而后输出定时器任务。原因则是Promise属于JavaScript引擎内部任务(宏任务),而setTimeout则是浏览器API(微任务),而引擎内部任务优先级高于浏览器API任务,所以有此结果。
错误处理
Promise会自动捕获内部异常,并交给rejected响应函数处理。
第一种错误处理
2.第二种错误处理
错误处理两种做法:
第一种:reject('错误信息').then(() => {}, () => {错误处理逻辑})
第二种:throw new Error('错误信息').catch( () => {错误处理逻辑})
推荐使用第二种方式,更加清晰好读,并且可以捕获前面所有的错误(可以捕获N个then回调错误)
catch() + then()
第一种情况:
结论:catch也会返回一个promise 实例,并且是 resolved 状态
第二种情况:
结论:抛出错误变为rejected状态,所以绕过两个then直接跑到最下面的catch
finally
finally()方法是Promise对象的原型方法,用于指定不论Promise对象状态如何都要被执行的回调函数,通常用来执行释放资源、清理操作等最终操作。
finally()方法只有一个参数,就是要执行的回调函数。这个回调函数在Promise对象状态变为已解决(resolved)或已拒绝(rejected)时都会被执行,无论如何都会执行。以下是一个使用finally()方法的例子:
function asyncFunction() {return new Promise((resolve, reject) => {// 模拟一个异步操作,2秒钟后将结果返回setTimeout(() => {resolve('success');}, 2000);});
}// 在异步操作结束后执行清理操作
asyncFunction().then((value) => {console.log('异步操作成功', value);// 在这里对异步操作的结果进行处理}).catch((error) => {console.error('异步操作失败', error);// 处理异步操作的错误情况}).finally(() => {console.log('清理操作已执行');// 在这里执行清理操作,无论异步操作成功还是失败都会执行});
promise 三个常用静态方法
Promise.all() 批量执行
Promise.all([p1, p2, p3])用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise,它接收一个数组作为参数
数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变
当所有的子Promise都完成,该Promise完成,返回值是全部值的数组
有任何一个失败,该Promise失败,返回值是第一个失败的子Promise结果
//切菜function cutUp() {console.log('开始切菜。');var p = new Promise(function (resolve, reject) { //做一些异步操作setTimeout(function () {console.log('切菜完毕!');resolve('切好的菜');}, 1000);});return p;}//烧水function boil() {console.log('开始烧水。');var p = new Promise(function (resolve, reject) { //做一些异步操作setTimeout(function () {console.log('烧水完毕!');resolve('烧好的水');}, 1000);});return p;}Promise.all([cutUp(), boil()]).then((result) => {console.log('准备工作完毕');console.log(result); // ["切好的菜", "烧好的水"]})
Promise.all()方法通常用于处理需要同时获取多个数据的情况,并将这些数据合并为一个结果返回。例如,在一个Web应用程序中,用户在提交订单时需要同时更新订单和用户信息,这时候就可以使用Promise.all()方法一次性向服务器发送两个请求,等待两个Promise都进入fulfilled状态后再进行下一步操作。
另外,Promise.all()方法也可以用于并行处理多个HTTP请求或I/O操作,以提高程序的执行效率。例如,我们从网站中获取多条数据,这些数据都需要通过HTTP请求来获取,在所有Promise进入fulfilled状态后,我们可以将这些数据进行合并,并对它们进行排序、过滤等操作。这样一来,我们就可以在不阻塞主线程的情况下,在较短的时间内获取到多个数据,提高了应用程序的响应速度和用户体验。
除了上述使用场景之外,Promise.all()方法还可以用于多个耗时操作的并行执行和等待,例如读取多个文件、并发执行多个函数等。总之,Promise.all()方法在项目中具有很多实际使用场景,可以帮助我们优化和改进代码的执行效率和用户体验。
Promise.race()
Promise.race()方法同样是将多个Promise实例包装成一个新的Promise实例,但是只要有一个Promise 实例状态发生变化,就将新的Promise实例的状态改变,且终值由第一个完成的 Promise提供。
const promise1 = new Promise((resolve, reject) => {setTimeout(() => resolve('promise1 resolved'), 2000);
});
const promise2 = new Promise((resolve, reject) => {setTimeout(() => resolve('promise2 resolved'), 1000);
});
const promise3 = new Promise((resolve, reject) => {setTimeout(() => resolve('promise3 resolved'), 3000);
});Promise.race([promise1, promise2, promise3]).then((value) => {console.log(value); // 'promise2 resolved'
});
Promise.race()方法也有许多实际使用场景。它可以用于处理需要快速获取结果的情况,例如,当我们向多个不同的服务器请求同一个资源时,我们可以使用Promise.race()方法来获取最快返回结果的服务器的响应,并忽略其他服务器的响应结果。或者,在一个Web应用程序中,我们需要在指定的时间内获取用户的同步输入和异步请求结果,我们可以使用Promise.race()方法同时监听用户输入事件和请求结果事件,一旦其中有一个事件触发,就可以立即返回响应结果,提高应用程序的响应速度和用户体验。
另外,Promise.race()方法还可以用于处理超时情况,例如,在一个HTTP请求的响应时间超过一定时间后,我们可以使用Promise.race()方法将该请求和一个延迟一定时间的Promise实例包装起来,一旦有一个Promise进入fulfilled状态,就可以立即返回响应结果。如果请求在规定的时间内仍未返回,则将其取消并返回一个错误信息给用户,以提高应用程序的可用性和稳定性。
Promise.any()
Promise.any()方法会对多个Promise进行竞争,直到有一个Promise进入Fulfilled状态,Promise实例返回该Promise的结果。如果所有Promise都进入Rejected状态,则返回失败状态,其中维护Promise及其状态的任何提示返回数组都是必需的。
const promises = [Promise.reject(1),Promise.reject(2),Promise.resolve(3),
];Promise.any(promises).then((value) => console.log(value)).catch((error) => console.log(error)); // 3
如果所有的promise都是reject的,就抛出异常:
const promises = [Promise.reject('error 1'),Promise.reject('error 2')
];
Promise.any(promises).then((value) => console.log(value)).catch((err) => console.log(err));
打印 AggregateError: All promises were rejected
Promise.any()方法可以用于处理多种资源竞争的情况,例如,在一个抢单系统中,多个用户需要争夺同一个订单,系统将同时向多个用户发送请求,并使用Promise.any()方法监听所有请求的状态,一旦有一个用户成功抢到订单,系统就立即返回订单信息并发送通知给该用户,从而提高了用户的参与度和系统的可用性。
除此之外,Promise.any()方法还可以用于指定默认值或备选方案,例如,在一个多语言网站中,我们需要从多个API获取多语言翻译结果,但有些API可能由于网络原因或其他问题无法正常工作,这时候我们就可以使用Promise.any()方法来一次性向多个API发送请求,并设置一个默认值或备选方案,一旦有一个API正常返回翻译结果,就立即返回结果给用户,如果所有API都无法正常工作,则返回默认值或备选方案。
拓展 async/await 同步代码异步操作,两者必须搭配使用
async
顾名思义,异步。async函数对 Generator 函数的改进,async 函数必定返回 Promise,我们把所有返回 Promise 的函数都可以认为是异步函数。特点体现在以下四点:
- 内置执行器
- 更好的语义
- 更广的适用性
- 返回值是 Promise
await
顾名思义,等待。正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。await后的Promise如果是reject状态, 那么整个async函数都会中断,后面的代码不执行。
混合使用
先看示例:
function sleep(ms) {return new Promise(function(resolve, reject) {setTimeout(resolve,ms);})
}
async function handle(){console.log("AAA")await sleep(5000)console.log("BBB")
}handle();// AAA
// BBB (5000ms后)
我们定义函数sleep,返回一个Promise。然后在handle函数前加上async关键词,这样就定义了一个async函数。在该函数中,利用await来等待一个Promise。
Promise优缺点
实战示例,回调地狱和promise对比:
/***第一步:找到北京的id第二步:根据北京的id -> 找到北京公司的id第三步:根据北京公司的id -> 找到北京公司的详情目的:模拟链式调用、回调地狱***/// 回调地狱// 请求第一个API: 地址在北京的公司的id$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city',success (resCity) {let findCityId = resCity.filter(item => {if (item.id == 'c1') {return item}})[0].id$.ajax({// 请求第二个API: 根据上一个返回的在北京公司的id “findCityId”,找到北京公司的第一家公司的idurl: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list',success (resPosition) {let findPostionId = resPosition.filter(item => {if(item.cityId == findCityId) {return item}})[0].id// 请求第三个API: 根据上一个API的id(findPostionId)找到具体公司,然后返回公司详情$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company',success (resCom) {let comInfo = resCom.filter(item => {if (findPostionId == item.id) {return item}})[0]console.log(comInfo)}})}})}})
// Promise 写法// 第一步:获取城市列表const cityList = new Promise((resolve, reject) => {$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city',success (res) {resolve(res)}})})// 第二步:找到城市是北京的idcityList.then(res => {let findCityId = res.filter(item => {if (item.id == 'c1') {return item}})[0].idfindCompanyId().then(res => {// 第三步(2):根据北京的id -> 找到北京公司的idlet findPostionId = res.filter(item => {if(item.cityId == findCityId) {return item}})[0].id// 第四步(2):传入公司的idcompanyInfo(findPostionId)})})// 第三步(1):根据北京的id -> 找到北京公司的idfunction findCompanyId () {let aaa = new Promise((resolve, reject) => {$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list',success (res) {resolve(res)}})})return aaa}// 第四步:根据上一个API的id(findPostionId)找到具体公司,然后返回公司详情
function companyInfo (id) {let companyList = new Promise((resolve, reject) => {$.ajax({url: 'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company',success (res) {let comInfo = res.filter(item => {if (id == item.id) {return item}})[0]console.log(comInfo)}})})
}
es6---Promise相关推荐
- 十分钟快速了解 ES6 Promise
转载自 十分钟快速了解 ES6 Promise 什么是Promise Promise最早由社区提出并实现,典型的一些库有Q,when, bluebird等:它们的出现是为了更好地解决JavaScrip ...
- 解读ES6 Promise
详解ES6 Promise异步 文章目录 详解ES6 Promise异步 前言 一.Promise是什么呢... 二.resolve 三.reject 四.then() & catch() 五 ...
- 流程控制: jQ Deferred 与 ES6 Promise 使用新手向入坑!
谢谢n͛i͛g͛h͛t͛i͛r͛e͛大大指出的关于Promise中catch用的不到位的错误,贴上大大推荐的文章Promise中的菜鸟和高阶错误,文章很详细说明了一些Promise使用中的错误和指导. ...
- es6 Promise是什么?
# es6 Promise是什么? 1. Promise 是一个构造函数 自带三个方法 all.resolve.reject,原型上(prototype)有then.catch等的几个常用的方法. ` ...
- ES6 — Promise基础用法详解(resolve、reject、then、catch,all,)
ES6 - Promise基础用法详解 Promise 是一个构造函数,它自身拥有all.reject.resolve这几个眼熟的方法, 原型上有then.catch等同样熟悉的方法. 所以,在开始一 ...
- ES6 promise 用法小结
ES6 promise 用法小结 Js 是一⻔单线程语言,早期解决异步问题,大部分是通过回调函数进行. 比如我们发送 ajax 请求,就是常见的一个异步场景,发送请求后,一段时间服务器给我们响应,然后 ...
- Vue进阶(四十五):精解 ES6 Promise 用法
文章目录 一.前言 二.链式操作用法 三.reject 用法 四.catch 用法 五.all 用法 六.race 用法 七.总结 八.拓展阅读 一.前言 复杂难懂概念先不讲,我们先简单粗暴地把Pro ...
- ES6 Promise原理
ES6 Promise原理 一.Promise是什么 二.为什么会有Promise 1.回调地狱 + 异步同步事件调用顺序带来的双重伤害 2.回调事件的分离 三.Promise的三种状态 1.reso ...
- 初探 es6 promise
javascript是单线程程序,所有代码都是单线程执行.导致javascript的网络请求都是异步执行,异步执行可以通过回调函数实现: setTimeout(callback,1000); func ...
- es6 --- Promise封装读取文件操作
Promise: es6中为了解决回调地狱问题而产生的 Promise的参数 Promise的参数是一个函数. 每个Promise在实例化时,都会立即执行参数里的函数 const p = new Pr ...
最新文章
- AIX的用户和组管理
- 加权残差连接ReZero
- placeholder兼容性问题以及用label代替placeholder
- IDEA第一个mybatis程序 mybatis增删查改操作 mybatis的map模糊查询
- codeforces1303 F. Number of Components(并查集+添_正序、删_逆序)
- kafka 重新分配节点_Kafka扩容节点和分区迁移
- enableEventValidation错误原因分析以及解决办法
- HW Eth-Trunk链路聚合
- WIFI安全测试之WPS(PIN)加密暴力破解
- c语言网格搜索,基于C
- 105份墨天轮“国产化迁移”精品文档汇总(含TiDB、openGauss、上云等)
- 四旋翼无人机飞行器基本知识(四旋翼无人机结构和原理+四轴飞行diy全套入门教程)
- “大数据”查询平台利用抖音导流,存个人信息泄露或倒卖风险
- 第四天作业发布时间:2021-05-31 09:57:49相关课程:RHCSA2021-05-22 
- 第11章 Linux的网络管理
- EasyNVR网页/微信播放RTSP摄像机HLS/RTMP播放时出现起播等待问题的优化过程
- Python 高效提取 HTML 文本的方法
- 深入理解JVM(三)——JVM之判断对象是否存活(引用计数算法、可达性分析算法,最终判定),Eclipse设置GC日志输出,引用
- 流媒体之色彩转换——RGB(X)与YUV之间转换
- 【洛谷习题】通往奥格瑞玛的道路
热门文章
- proftpd ldap mysql_安装proftpd+ldap报错
- 小程序 订阅消息 wx.requestSubscribeMessage 允许 拒绝 情况的返回 结果
- Android 高仿微信实时聊天 基于百度云推送
- Router中如何设置光标以全屏十字架显示
- Pycharm2018.2永久破解
- Three.js学习七——播放模型动画时模型沿着轨迹移动
- vue在生产环境、测试环境和开发环境,三种环境下配置不同的api地址
- Win7系统没有音量图标,系统图标为灰色打不开的解决方法
- 从键盘输入一个不多于3位的正整数,要求:求出它是几位数;分别打印出每一位数字;按逆序打印出各位数字
- 软件定义汽车的关键—车载操作系统