Promise
- 背景
简单了解event loop
+javascript上, 所有同步任务都在主线程上执行,也可以理解为存在一个“执行栈”。- 主线程外,还有一个“任务队列”,任务队列的作用,就在等待异步任务的结果,只要异步任务有了运行结果,就会加入到“任务队列”中。
- 一旦执行栈中所有同步任务执行完毕,就从 任务队列 中读取“任务”加入到“执行栈”中。
主线程不断的在循环上面的步骤。
(function() { console.log('这是开始'); setTimeout(function cb() { console.log('这是来自第一个回调的消息'); setTimeout(function cb3() { console.log("这是来自第三个回调的消息"); }) }); console.log('这是一条消息'); setTimeout(function cb1() { console.log('这是来自第二个回调的消息'); setTimeout(function cb3() { console.log("这是来自第四个回调的消息"); }) }); console.log('这是结束'); })();
什么是Promise
为什么要使用Promise
- 举几个栗子
最简单的Promise
这里看起来很简单,但有两点是要注意的
- 一定要resolve或者reject,否则你的then是永远也执行不到的。
- promise的状态一定改变后,就再也不会发生变化了。
let promise = new Promise(function(resolve, reject) {
resolve("success");
reject("fail");
});
promise.then((value) => {
console.log(value);
}).catch((reason) => {
console.log(reason);
});
输出结果
这个例子也充分证明了Promise只有一个状态结果,并且是不可变的
经典的回调地狱
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback);}, failureCallback);
promise的写法
doSomething()
.then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
// 配合箭头函数
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
function* fuc() {
const result = yield doSomething()
const newResult = yield doSomethingElse(result)
const finalResult = yield doThirdThing(newResult)
}
const test = fuc()
const result = test.next() // {value: 1, done: false}
const newResult = test.next(result.value) // {value: 1, done: false}
const finalResult = test.next(newResult.value) // {value: 1, done: true}
test.next() // {value: undefined, done: true}
async function useAsyncAwait() {
try {
const result = await doSomething()
const newResult = await doSomethingElse()
const finalResult = await doThirdThing()
console.log('Got the final result: ' + finalResult)
} catch (e) {
Console.error('exception: ', e)
}
}
- 如何包装promise
function getJSON(url) {
return new Promise(function(resolve, reject){
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('getJSON: `' + url + '` Failed with status: [' + this.status + ']'));
}
}
};
});
}
getJSON('/posts.json')
.then((json) =>{
// on fulfillment
})
.catch((error) => {
// on rejection
console.log(error)
});
多个promise顺序执行
promise的then,是可以保证按照你看到的顺序执行的
getJSON('/ray/api/a/server/ping')
.then((json) =>{
// on fulfillment
console.log('ping a result: ' + JSON.stringify(json));
})
.then(() => getJSON('/ray/api/b/server/ping'))
.then(json => {
console.log('ping b result: ' + JSON.stringify(json))
})
.catch((error) => {
// on rejection
console.log(error)
});
// ping a result: {"status":"OK","serverTime":1573554742633}
// ping b result: {"status":"OK","serverTime":1573554742667}
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一个then
console.log(value); // 1
return value*2;
}).then(function(value){ //第二个then
console.log(value); // 2
}).then(function(value){ //第三个then
console.log(value); // underfined
return Promise.resolve('resolve');
}).then(function(value){ //第四个then
console.log(value); // 'resolve'
return Promise.reject('reject');
}).then(function(value){ //第五个then
console.log('resolve: '+ value); // 不到这里,没有值
}, function(err){
console.log('reject: ' + err); // 'reject'
})
引用一些第三方库 比如 Bluebird
比如
mapSeries => 同步的执行所有异步任务,
all => 等待并发的任务全部执行完毕,
any => 多个异步任务中,有一个执行完毕就结束了。
==
npm install bluebird
import * as Promise from "bluebird";
let data = ['a', 'c', 'b', 'e', 'd']
Promise.mapSeries(data, (d) => getJSON(d) ).then((result) => {console.log(result)})
// 执行结果应该是什么
1. 如果没有修改代码 => 只执行了第一个a,后面的都应该第一个a出错,所以不继续执行了
2. 如果将getJSON里的reject改成resoleve => a c b e d的出错log会按顺序打印
- 多个promise并发执行
Promise.all([ getJSON('/ray/api/a/server/ping'), getJSON('/ray/api/b/server/ping')]).then((result) => {
console.log('ping result: ' + JSON.stringify(result));
})
// ping result: [{"status":"OK","serverTime":1573554934072},{"status":"OK","serverTime":1573554934070}]
- 多个promise之间的竞争
promise 无法取消执行
new Promise 里的任务会立即执行
const delay = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('timeout');
resolve('timeout');
}, 3000)
})
Promise.race([ getJSON('/ray/api/a/server/ping'), delay]).then((result) => {
console.log('ping result: ' + JSON.stringify(result));
})
// 思考下这里的timeout会不会打印
- Promise 的穿透
promise 的then必须接收函数,否则会穿透。
// 这里`Promise.resolve(2)`并不是函数,所以上一个函数的结果会穿透到下一个
Promise.resolve(1).then(Promise.resolve(2)).then((v) => {
console.log(v)
})
// 语法错误
Promise.resolve(1).then(return Promise.resolve(2)).then((v) => {
console.log(v)
})
// 穿透
Promise.resolve(1).then(null).then((v) => {
console.log(v)
})
// 语法错误
Promise.resolve(1).then(return 2).then((v) => {
console.log(v)
})
// then会返回新的promise,并且带上他返回的结果
Promise.resolve(1).then(() => {
return 2
}).then((v) => {
console.log(v)
})
当then()受非函数的参数时,会解释为then(null),这就导致前一个Promise的结果穿透到下面一个Promise。所以要提醒你自己:永远给then()传递一个函数参数。
错误的捕获
一旦捕获到错误,promise的then会继续执行
catch会检查promis链上位于它之前的每个地方(then或者其他异步操作)。如果在它之前还有其他catch,那么起点就是上一个catch。
var p1 = new Promise( function(resolve,reject){
foo.bar();
resolve( 1 );
});
p1.then(
function(value){
console.log('p1 then value: ' + value);
},
function(err){
console.log('p1 then err: ' + err);
}
).then(
function(value){
console.log('p1 then then value: '+value);
},
function(err){
console.log('p1 then then err: ' + err);
}
);
轻喷!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。