简单了解event loopjavascript
+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('这是结束'); })();
什么是Promisejava
为何要使用Promisenode
最简单的Promisenpm
这里看起来很简单,但有两点是要注意的
- 必定要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只有一个状态结果,而且是不可变的json
经典的回调地狱api
回调函数的写法promise
多个异步事务多级依赖,回调函数会造成多级的嵌套,代码就会变成金字塔结构,不只可读性不高,并且在后期的维护,调试或者重构上,都充满了风险。并发
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback);}, failureCallback);
promise的写法
解决了嵌套问题,thenable能够更好的支持链式调用,但仍是能看到回调的影子
更加简便的错误处理
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);
generator写法
有一个暂停状态,只有咱们激活next,才会去执行下一个异步任务
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/await的写法
这个语法上更加简单,看起来更像同步任务,并且不须要关心执行状态。
我理解这里只是对generator的一个包装,里面应该有个递归函数,在执行next,执行done。
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) } }
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}
Promise 的链式调用
举一个更具体的例子,体现thenable, promise的状态不可变
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.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 没法取消执行
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 的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); } );