Javascript promise异步编程浅析
promise 是什么
Promise 是异步编程的一种解决方案,可以替代传统的解决方案–回调函数和事件。ES6 统一了用法,并原生提供了 Promise 对象。作为对象,Promise 有以下两个特点:
(1)对象的状态不受外界影响。
(2)一旦状态改变了就不会再变,也就是说任何时候 Promise 都只有一种状态。
Promise 有三种状态,分别是 Pending (进行中)、Resolved (已完成)、Rejected (已失败)。Promise 从 Pending 状态开始,如果成功就转到成功态,并执行 resolve 回调函数;如果失败就转到失败状态并执行 reject 回调函数。
可以通过 Promise 的构造函数创建 Promise 对象
var promise = new Promise((resolve,reject) => { setTimeout(()=>{ console.log("hello world") }, 2000) })
Promise 构造函数接受一个函数作为参数,该函数的两个参数是 resolve ,reject,它们由 JavaScript 引擎提供。其中 resolve 函数的作用是当 Promise 对象转移到成功,调用 resolve 并将操作结果作为其参数传递出去;reject 函数的作用是当 Promise 对象的状态变为失败时,将操作报出的错误作为参数传递出去。如下代码:
function greet(){ var promise = new Promise(function(resolve,reject){ var greet = "hello world" resolve(greet) }) return promise } greet().then(v=>{ console.log(v)//* })
Promise 的 then 方法,promise 的 then 方法带有一下三个参数:成功的回调,失败的回调,前进的回调。一般情况下只需要实现第一个,后面的是可选的。Promise 中最为重要的状态,通过 then 的状态传递可以实现的回调函数链式操作的实现。先执行以下代码:
function greet () { var promise = new Promise (function(resolve, reject){ var greet = "hello world" resolve(greet) }) return promise } var p = greet().then(v => { console.log(v) // Promise { <pending> } }) console.log(p) // hello world
catch 用法
function judgeNumber(num){ var promise1 = new Promise(function(resolve,reject){ num =5; if(num<5){ resolve("num小于5,值为:"+num); }else{ reject("num不小于5,值为:"+num); } }); return promise1; } judgeNumber().then( function(message){ console.log(message); } ) .catch(function(message){ console.log(message); })
Promise 的 all 方法提供了并行执行异步操作的能力,在 all 中所有异步操作结束后才执行回调。
function p1(){ var promise1 = new Promise(function(resolve,reject){ console.log("p1的第一条输出语句"); console.log("p1的第二条输出语句"); resolve("p1完成"); }) return promise1; } function p2(){ var promise2 = new Promise(function(resolve,reject){ console.log("p2的第一条输出语句"); setTimeout(()=>{console.log("p2的第二条输出语句");resolve("p2完成")},2000); }) return promise2; } function p3(){ var promise3 = new Promise(function(resolve,reject){ console.log("p3的第一条输出语句"); console.log("p3的第二条输出语句"); resolve("p3完成") }); return promise3; } Promise.all([p1(),p2(),p3()]).then(function(data){ console.log(data); }) p1的第一条输出语句 p1的第二条输出语句 p2的第一条输出语句 p3的第一条输出语句 p3的第二条输出语句 p2的第二条输出语句 ['p1完成', 'p2完成', 'p3完成']
在 all 中的回调函数中,等到所有的 Promise 都执行完,再来执行回调函数,race 则不同它等到第一个 Promise 改变状态就开始执行回调函数。将上面的all
改为race
,得到
Promise.race([p1(),p2(),p3()]).then(function(data){ console.log(data); })
如何实现一个 promise
(function(window,undefined){ // resolve 和 reject 最终都会调用该函数 var final = function(status,value){ var promise = this, fn, st; if(promise._status !== 'PENDING') return; // 所以的执行都是异步调用,保证then是先执行的 setTimeout(function(){ promise._status = status; st = promise._status === 'FULFILLED' queue = promise[st ? '_resolves' : '_rejects']; while(fn = queue.shift()) { value = fn.call(promise, value) || value; } promise[st ? '_value' : '_reason'] = value; promise['_resolves'] = promise['_rejects'] = undefined; }); } //参数是一个函数,内部提供两个函数作为该函数的参数,分别是resolve 和 reject var Promise = function(resolver){ if (!(typeof resolver === 'function' )) throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); //如果不是promise实例,就new一个 if(!(this instanceof Promise)) return new Promise(resolver); var promise = this; promise._value; promise._reason; promise._status = 'PENDING'; //存储状态 promise._resolves = []; promise._rejects = []; // var resolve = function(value) { //由於apply參數是數組 final.apply(promise,['FULFILLED'].concat([value])); } var reject = function(reason){ final.apply(promise,['REJECTED'].concat([reason])); } resolver(resolve,reject); } Promise.prototype.then = function(onFulfilled,onRejected){ var promise = this; // 每次返回一个promise,保证是可thenable的 return new Promise(function(resolve,reject){ function handle(value) { // 這一步很關鍵,只有這樣才可以將值傳遞給下一個resolve var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value; //判断是不是promise 对象 if (ret && typeof ret ['then'] == 'function') { ret.then(function(value) { resolve(value); }, function(reason) { reject(reason); }); } else { resolve(ret); } } function errback(reason){ reason = typeof onRejected === 'function' && onRejected(reason) || reason; reject(reason); } if(promise._status === 'PENDING'){ promise._resolves.push(handle); promise._rejects.push(errback); }else if(promise._status === FULFILLED){ // 状态改变后的then操作,立刻执行 callback(promise._value); }else if(promise._status === REJECTED){ errback(promise._reason); } }); } Promise.prototype.catch = function(onRejected){ return this.then(undefined, onRejected) } Promise.prototype.delay = function(ms,value){ return this.then(function(ori){ return Promise.delay(ms,value || ori); }) } Promise.delay = function(ms,value){ return new Promise(function(resolve,reject){ setTimeout(function(){ resolve(value); console.log('1'); },ms); }) } Promise.resolve = function(arg){ return new Promise(function(resolve,reject){ resolve(arg) }) } Promise.reject = function(arg){ return Promise(function(resolve,reject){ reject(arg) }) } Promise.all = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to all.'); } return Promise(function(resolve,reject){ var i = 0, result = [], len = promises.length, count = len //这里与race中的函数相比,多了一层嵌套,要传入index function resolver(index) { return function(value) { resolveAll(index, value); }; } function rejecter(reason){ reject(reason); } function resolveAll(index,value){ result[index] = value; if( --count == 0){ resolve(result) } } for (; i < len; i++) { promises[i].then(resolver(i),rejecter); } }); } Promise.race = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to race.'); } return Promise(function(resolve,reject){ var i = 0, len = promises.length; function resolver(value) { resolve(value); } function rejecter(reason){ reject(reason); } for (; i < len; i++) { promises[i].then(resolver,rejecter); } }); } window.Promise = Promise; })(window);
async await
async 表示这是一个 async 函数, await 只能用在 async 函数里面,不能单独使用
async 返回的是一个 Promise 对象,await 就是等待这个 promise 的返回结果后,再继续执行
await 等待的是一个 Promise 对象,后面必须跟一个 Promise 对象,但是不必写 then(),直接就可以得到返回值
async/await 的优点
方便级联调用:即调用依次发生的场景;
同步代码编写方式:Promise 使用 then 函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await 从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯;
多个参数传递:Promise 的 then 函数只能传递一个参数,虽然可以通过包装成对象来传递多个参数,但是会导致传递冗余信息,频繁的解析又重新组合参数,比较麻烦;async/await 没有这个限制,可以当做普通的局部变量来处理,用 let 或者 const 定义的块级变量想怎么用就怎么用,想定义几个就定义几个,完全没有限制,也没有冗余工作;
同步代码和异步代码可以一起编写:使用 Promise 的时候最好将同步代码和异步代码放在不同的 then 节点中,这样结构更加清晰;async/await 整个书写习惯都是同步的,不需要纠结同步和异步的区别,当然,异步过程需要包装成一个 Promise 对象放在 await 关键字后面;
基于协程:Promise 是根据函数式编程的范式,对异步过程进行了一层封装,async/await 基于协程的机制,是真正的“保存上下文,控制权切换……控制权恢复,取回上下文”这种机制,是对异步过程更精确的一种描述;
async/await 是对 Promise 的优化:async/await 是基于 Promise 的,是进一步的一种优化,不过在写代码时,Promise 本身的 API 出现得很少,很接近同步代码的写法
到此这篇关于Javascript promise异步编程浅析的文章就介绍到这了,更多相关Js promise异步内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【圆形情况】
这篇文章主要介绍了JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法,结合实例形式详细分析了圆形包盒情况下的碰撞检测算法相关原理与实现技巧,需要的朋友可以参考下2018-12-12
最新评论