Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 api,各种异步操作都可以用同样的方法进行处理。简单来说,promise的作用就是将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
① 对象的状态不受外界影响:promise异步操作有三种状态:进行中,已成功,已失败。只有异步操作才能改变这个状态。 ②一变则不变:promise状态一旦改变,就不会再发生变化,promise对象改变的两种可能,进行中—>已成功,进行中—>已失败。
promise对象是一个构造函数,用来生成promise实例
例子:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
其中接受的参数是resolve和reject两个函数
resolve的作用:将promise对象的状态由进行中—>已完成。并将异步操作的结果作为参数传递出去
rejected的作用:将promise对象的状态由进行中—>已失败,并将异步失败的原因作为参数传递出去。
注意:调用resolve或reject并不会终结promise的参数函数的执行
例子:
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
上面代码调用了resolve(1)以后,后面的console(2)还是会执行,并且会首先打印出来。这是因为立即resolved的promise是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
promise实例生成后,用then方法分别指定resolved状态和rejucted状态的回调函数。
例子:
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then方法可以接受两个回调函数作为参数,第一个回调函数是当promise对象状态是resolve(已完成)的时候调用,第二个回调函数(可选)是当promise对象状态是reject(已失败)的时候调用。
如例子:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then((value) => {
console.log(value);
});
// 结果是done
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法
例子
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("resolved: ", comments);
}, function funcB(err){
console.log("rejected: ", err);
});
上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB。
promise对象中,如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数处理这个错误,另外,then方法指定的回调函数,如果运行中抛出错误也会被catch方法捕获。
例子:
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
promise对象的错误具有“冒泡”性质,会一直向后传,直到被捕获,也就是说,会跳过中间的then函数
例子:
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
finally方法用于指定不管promise对象最后状态如何,都会执行的操作。
例子
server.listen(port)
.then(function () {
// ...
})
.finally(server.stop);
例子是服务器使用promise处理请求,然后使用finally()方法关掉服务器。
promise.all方法用于将多个promise实例,包装成一个新的promise实例。
比如:const p = Promise.all([p1, p2, p3]);
Promise.all方法,接受的是一个数组作为参数,其中的元素都是promise实例,如果不是,则会自动将参数转变为promie实例。
p的状态是有它的数组里面的元素决定的,分两种状态(用上面举例)
①只有p1 p2 p3的状态都变成fulfilled(已完成)的状态才会变成fulfilled(已完成),此时p1 p2 p3的返回值组成一个数组,传递给p的回调函数。
②只有p1 p2 p3之中,有一个被rejucted(未完成),p的状态就会变成rejected(未完成),此时第一个被reject的实例的返回值,会传递给p的回调函数。
例子:
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了enter code here
Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.race([p1, p2, p3]);
如果p1 p2 p3不是promise实例,也会自动转变成promise实例
与promise.all不同的是,上面代码中,只用p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
async的引入,使得异步操作变得更加方便,那async函数是什么,其实它是Generator函数的语法糖。使异步函数、回调函数在语法上看上去更像同步函数。Generator这里就不介绍了。我们直接来学习async
async返回值是一个promise对象,因此可以使用then方法添加回调函数,当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的内容。
例子:
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
async函数的使用形式
//函数声明
async function foo(){}
//函数表达式
const foo = async function(){};
//对象的方法
let obj = {async foo(){}};
obj.foo().then(...)
//class的方法
class Storage{
consttuctor(){
this.cachePromise=caches.open('avatars');
}
async getAvatar(name){
const cache = await this.cachePromise;
return cache.match('/avatars/${name}.jpg')};
}
}
const storage =new Storage();
storage.getAvatar('jake').then(....);
}
}
const storage =new Storage();
storage.getAvatar('jake').then(...)
//箭头函数
const foo =async()=>{};
async 函数内部return语句返回的值,会成为then方法调用函数的参数。
例子:
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"
正常情况下,await命令后面跟着的是一个promise对象,如果不是会自动转化为promise对象
例子:
async function f(){
return await 123;
}
f().then(v =>console.log(v))
//123
当一个await语句后面的promise变为reject,那么整个函数都会中断执行。
例子:
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}
如果await 后面的异步操作有错,那么等同于async函数返回的promis对象被reject (上文讲promise对象的时候有提到过,冒泡性质) 例子:
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
使用try ....catch代码块课防止出错。
例子:
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}
也可以将多个await命令都放在try..catch结构中
async function main() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
①await命令只能用在async函数中,用在普通函数中会报错。
javascript中alert是Bom中的成员函数,alert对话框是模态的,具有阻塞性质的,不点击是不会执行后续代码的。js的阻塞是指在调用结果返回之前,当前线程会被挂起, 只有在得到结果之后才会继续执行。
如何优化async代码?更好的编写async函数:使用return Promise.reject()在async函数中抛出异常,让相互之间没有依赖关系的异步函数同时执行,不要在循环的回调中/for、while循环中使用await,用map来代替它
Javascript语言的执行环境是单线程,异步模式非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。
js异步加载又被称为非阻塞加载,浏览器在下载JS的同时,还会进行后续页面处理。那么如何实现js异步加载呢?下面整理了多种实现方案供大家参考。异步加载js方案:Script Dom Element、onload时的异步加载、$(document).ready()、async属性、defer属性、es6模块type=module属性
回调函数方式:将异步方法如readFile封装到一个自定义函数中,通过将异步方法得到的结果传给自定义方法的回调函数参数。事件驱动方式:使用node events模块,利用其EventEmitter对象
JavaScript引擎是基于单线程 (Single-threaded) 事件循环的概念构建的,同一时刻只允许一个代码块在执行,所以需要跟踪即将运行的代码,那些代码被放在一个任务队列 (job queue) 中
传统的异步解决方案采用回调函数和事件监听的方式,而这里主要记录两种异步编程的新方案:ES6的新语法Promise;ES2017引入的async函数;Generator函数(略)
JS本身是一门单线程的语言,所以在执行一些需要等待的任务(eg.等待服务器响应,等待用户输入等)时就会阻塞其他代码。如果在浏览器中JS线程阻塞了,浏览器可能会失去响应,从而造成不好的用户体验。
请实现如下的函数,可以批量请求数据,所有的URL地址在urls参数中,同时可以通过max参数 控制请求的并发度。当所有的请求结束后,需要执行callback回调。发请求的函数可以直接使用fetch。
将setState()认为是一次请求而不是一次立即执行更新组件的命令。为了更为可观的性能,React可能会推迟它,稍后会一次性更新这些组件。React不会保证在setState之后,能够立刻拿到改变的结果。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!