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构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由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响应函数处理。

  1. 第一种错误处理

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相关推荐

  1. 十分钟快速了解 ES6 Promise

    转载自 十分钟快速了解 ES6 Promise 什么是Promise Promise最早由社区提出并实现,典型的一些库有Q,when, bluebird等:它们的出现是为了更好地解决JavaScrip ...

  2. 解读ES6 Promise

    详解ES6 Promise异步 文章目录 详解ES6 Promise异步 前言 一.Promise是什么呢... 二.resolve 三.reject 四.then() & catch() 五 ...

  3. 流程控制: jQ Deferred 与 ES6 Promise 使用新手向入坑!

    谢谢n͛i͛g͛h͛t͛i͛r͛e͛大大指出的关于Promise中catch用的不到位的错误,贴上大大推荐的文章Promise中的菜鸟和高阶错误,文章很详细说明了一些Promise使用中的错误和指导. ...

  4. es6 Promise是什么?

    # es6 Promise是什么? 1. Promise 是一个构造函数 自带三个方法 all.resolve.reject,原型上(prototype)有then.catch等的几个常用的方法. ` ...

  5. ES6 — Promise基础用法详解(resolve、reject、then、catch,all,)

    ES6 - Promise基础用法详解 Promise 是一个构造函数,它自身拥有all.reject.resolve这几个眼熟的方法, 原型上有then.catch等同样熟悉的方法. 所以,在开始一 ...

  6. ES6 promise 用法小结

    ES6 promise 用法小结 Js 是一⻔单线程语言,早期解决异步问题,大部分是通过回调函数进行. 比如我们发送 ajax 请求,就是常见的一个异步场景,发送请求后,一段时间服务器给我们响应,然后 ...

  7. Vue进阶(四十五):精解 ES6 Promise 用法

    文章目录 一.前言 二.链式操作用法 三.reject 用法 四.catch 用法 五.all 用法 六.race 用法 七.总结 八.拓展阅读 一.前言 复杂难懂概念先不讲,我们先简单粗暴地把Pro ...

  8. ES6 Promise原理

    ES6 Promise原理 一.Promise是什么 二.为什么会有Promise 1.回调地狱 + 异步同步事件调用顺序带来的双重伤害 2.回调事件的分离 三.Promise的三种状态 1.reso ...

  9. 初探 es6 promise

    javascript是单线程程序,所有代码都是单线程执行.导致javascript的网络请求都是异步执行,异步执行可以通过回调函数实现: setTimeout(callback,1000); func ...

  10. es6 --- Promise封装读取文件操作

    Promise: es6中为了解决回调地狱问题而产生的 Promise的参数 Promise的参数是一个函数. 每个Promise在实例化时,都会立即执行参数里的函数 const p = new Pr ...

最新文章

  1. AIX的用户和组管理
  2. 加权残差连接ReZero
  3. placeholder兼容性问题以及用label代替placeholder
  4. IDEA第一个mybatis程序 mybatis增删查改操作 mybatis的map模糊查询
  5. codeforces1303 F. Number of Components(并查集+添_正序、删_逆序)
  6. kafka 重新分配节点_Kafka扩容节点和分区迁移
  7. enableEventValidation错误原因分析以及解决办法
  8. HW Eth-Trunk链路聚合
  9. WIFI安全测试之WPS(PIN)加密暴力破解
  10. c语言网格搜索,基于C
  11. 105份墨天轮“国产化迁移”精品文档汇总(含TiDB、openGauss、上云等)
  12. 四旋翼无人机飞行器基本知识(四旋翼无人机结构和原理+四轴飞行diy全套入门教程)
  13. “大数据”查询平台利用抖音导流,存个人信息泄露或倒卖风险
  14. 第四天作业发布时间:2021-05-31 09:57:49相关课程:RHCSA2021-05-22 
  15. 第11章 Linux的网络管理
  16. EasyNVR网页/微信播放RTSP摄像机HLS/RTMP播放时出现起播等待问题的优化过程
  17. Python 高效提取 HTML 文本的方法
  18. 深入理解JVM(三)——JVM之判断对象是否存活(引用计数算法、可达性分析算法,最终判定),Eclipse设置GC日志输出,引用
  19. 流媒体之色彩转换——RGB(X)与YUV之间转换
  20. 【洛谷习题】通往奥格瑞玛的道路

热门文章

  1. proftpd ldap mysql_安装proftpd+ldap报错
  2. 小程序 订阅消息 wx.requestSubscribeMessage 允许 拒绝 情况的返回 结果
  3. Android 高仿微信实时聊天 基于百度云推送
  4. Router中如何设置光标以全屏十字架显示
  5. Pycharm2018.2永久破解
  6. Three.js学习七——播放模型动画时模型沿着轨迹移动
  7. vue在生产环境、测试环境和开发环境,三种环境下配置不同的api地址
  8. Win7系统没有音量图标,系统图标为灰色打不开的解决方法
  9. 从键盘输入一个不多于3位的正整数,要求:求出它是几位数;分别打印出每一位数字;按逆序打印出各位数字
  10. 软件定义汽车的关键—车载操作系统