前端异步技术之Promise

这篇具有很好参考价值的文章主要介绍了前端异步技术之Promise。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

从事前端的朋友或多或少的接触过Promise,当代码中回调函数层级过多你就会发现Promise异步编程的魅力,相信此文一定能帮你排忧解惑!

Promise概念

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一
或许是笔者理解能力有限,对官方术语怎么也感受不到亲切,下面我来用通俗易懂的语言解释下:
Promise是一个包含三种状态的对象(pending、fulfilled、rejected),可以链式的处理异步请求(then方法)并能很好地处理异常问题,是解决回调地狱的良好方案之一。
回调函数处理多层异步示例
$.ajax({
    url: url1,
    success: function(rsp){
        $.ajax({
           url: url2,
           success: function(rsp){
               $.ajax({
                  url: url3,
                  success: function(rsp){
                      //do sth
                  },
                  error: function(error){
                  }
              });
           },
           error: function(error){
           }
       });
    },
    error: function(error){
    }
});
将promise封装在$.ajax中
$.ajax = function(config){
    return new Promise(function(resolve, reject){
        //1省略...
        xmlhttp.onreadystatechange = function(){
            if(xmlhttp.status==200){
                resolve(rspData);
            }else{
                reject(xmlhttp.statusText);
            }
        };
        //2省略...
    })
}
$.ajax({url: url1}).then(function(val){
    return $.ajax({url: val.url})
}).then(function(val){
    return $.ajax({url: val.url})
}).catch(function(err){
    console.log(err);
}}
封装好的Promise处理异步可读性可维护性以及代码美观度不言而喻

Promise API

'new' Promise

//pending状态的promise
var promise = new Promise(function(resolve, reject){
    //do sth
})
//fulfilled状态的promise
var promise = Promise.resolve(1).then(function resolve(value){console.log(value)});
// var promise = new Promise(function(resolve){resolve(1)})
//rejected状态的promise
var promise = Promise.reject(new Error('error')).catch(function(error){console.error(error)});
// var promise = new Promise(function(resolve,reject){resolve(new Error('error'))})

Promise.prototype.then

Promise#then
promise.then(onFulfilled, onRejected)
返回一个新的promise。这里经常会有一个疑问:为什么不返回原来的promise,个人是这样认为的,若返回同一个promise则状态不一致,promise规范说明当pending至fulfilled/rejected时状态确定后不能再改变。

Promise.prototype.catch

Promise#catch
promise.catch(function(error){
    throw new Error(error);
})
注意:IE8及以下版本会出现 identifier not found 的语法错误,可将点标记法改为中括号标记法
promise['catch'](function(error){
    throw new Error(error);
})
rejected状态的promise抛出异常
相当于
promise.then(undefined, onRejected)
then & catch 结合示例
promise.then(function f1(value){
    //do sth 1
}).then(function f2(value){
    //do sth 2
}).then(function f3(value){
    //do sth 3
}).catch(function(error){
    console.log(error);
})

Promise.prototype.finally

promise.finally(onFinally)
返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行

Promise.all

promise.all([promise1, promise2, promise3]).then(resolve);
示例
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
var startDate = Date.now();
// 所有promise变为resolve后程序退出
Promise.all([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (values) {
    console.log(Date.now() - startDate + 'ms');
    // 约128ms
    console.log(values);    // [1,32,64,128]
});
在接收到所有的对象promise都变为 FulFilled 返回一个resolve(array),或者 某一个promise对象变成Rejected 状态返回resolve(err)
传递给 Promise.all 的promise并不是一个个的顺序执行的,而是同时开始、并行执行的。

Promise.race

promise.race([promise1, promise2]).then(resolve, reject)
示例
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (value) {
    console.log(value);    // => 1
});
只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。

Promise polyfill & Test

promise-polyfill.js

学习完Promise后,必定要重写Promise,后续遇到浏览器环境不支持也可有的放矢
代码如下
/**
 * @author chenchangyuan
 * @date 2019-02-23
 * */
function Promise(executor){
    if(typeof executor !== 'function'){
        throw new Error('executor is not a function');
    }
    var self = this;
    self.state = 'pending';//pending fulfilled rejected
    self.value = null;
    self.reason = null;
    self.callbackResolveFn = [];
    self.callbackRejectFn = [];
    function resolve(value){
        if(self.state === 'pending'){
            self.state = 'fulfilled';
            self.value = value;
            self.callbackResolveFn.forEach(function(fn){
                fn();
            });
        }
    }
    function reject(reason){
        if(self.state === 'pending'){
            self.state = 'rejected';
            self.reason = reason;
            self.callbackRejectFn.forEach(function(fn){
                fn();
            });
        }
    }
    try{
        executor(resolve, reject);
    }catch(err){
        reject(err);
    }
}
//回溯函数
function resolvePromise(promise, x, resolve, reject){
    if(promise === x) return reject(new TypeError('循环引用'));
    var flag = false;
    if(x !== null && (typeof x === 'object' || typeof x === 'function')){
        try{
            var then = x.then;
            if(typeof then === 'function'){
                then.call(x, function(val){
                    if(flag) return;
                    flag = true;
                    resolvePromise(promise, val, resolve, reject);
                }, function(err){
                    if(flag) return;
                    flag = true;
                    reject(err);
                });
            }else{
                resolve(x);
            }
        } catch(err){
            if(flag) return;
            flag = true;
            reject(err);
        }

    }else{
        resolve(x);
    }
}
//返回一个新的promise(pending:push(fn),fulfilled:resolve(val),rejected:reject(reason))
Promise.prototype.then = function(onFulfilled, onRejected){
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
        return value;
    };
    onRejected = typeof onRejected === 'function' ? onRejected : function(err){
        throw new Error(err);
    };
    var self = this,
        promise2;
    if(self.state === 'fulfilled'){
        promise2 = new Promise(function(resolve, reject){
            setTimeout(function(){
                try{
                    //将x处理成一个原始值
                    var x = onFulfilled(self.value);
                    resolvePromise(promise2, x, resolve, reject);
                } catch(e){
                    reject(e);
                }
            })
        })
    }
    if(self.state === 'rejected'){
        promise2 = new Promise(function(resolve, reject){
            setTimeout(function(){
                try{
                    //将x处理成一个原始值
                    var x = onRejected(self.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch(e){
                    reject(e);
                }
            })
        })
    }
    if(self.state === 'pending'){
        promise2 = new Promise(function(resolve, reject){
            self.callbackResolveFn.push(function(){
                setTimeout(function(){
                    try{
                        //将x处理成一个原始值
                        var x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch(e){
                        reject(e);
                    }
                })
            });
            self.callbackRejectFn.push(function(){
                setTimeout(function(){
                    try{
                        //将x处理成一个原始值
                        var x = onRejected(self.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch(e){
                        reject(e);
                    }
                })
            });
        })
    }
    return promise2;
}
Promise.prototype['catch']= function (callback) {
    return this.then(undefined, callback)
}
Promise.all = function (promises) {
    return new Promise(function (resolve, reject) {
        let arr = [];
        let i = 0;
        function processData(index, y) {
            arr[index] = y;
            if (++i === promises.length) {
                resolve(arr);
            }
        }
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(function (y) {
                processData(i, y)
            }, reject)
        }
    })
}
Promise.race = function (promises) {
    return new Promise(function (resolve, reject) {
        for (var i = 0; i < promises.length; i++) {
            promises[i].then(resolve,reject)
        }
    });
}
Promise.resolve = function(value){
    return new Promise(function(resolve,reject){
        resolve(value);
    });
}
Promise.reject = function(reason){
    return new Promise(function(resolve,reject){
        reject(reason);
    });
}
Promise.defer = Promise.deferred = function () {
    var d = {};
    d.promise = new Promise(function (resolve, reject) {
        d.resolve = resolve;
        d.reject = reject;
    });
    return d
}
module.exports = Promise;

promise-aplus-tests

由于是参(抄)考(袭)前辈的polyfill,自己编码测试时出现了两处错误,ES6 Promise 规范的2.3.1和2.3.4

2.3.1

前端异步技术之Promise

2.3.4

前端异步技术之Promise

经过改正测试成功

前端异步技术之Promise

后记

你们的支持是我最大的动力,熬夜码字不易,如果此文对你有帮助,请不吝star--->https://github.com/chenchangyuan/promise

有兴趣加笔者好友的同学请扫描下方二维码(1.本人微信,2.微信公众号,3.技术交流微信群),愿与您成为好友共同探讨技术,畅聊生活!

 

前端异步技术之Promise

参考资料

https://promisesaplus.com/

http://liubin.org/promises-book

https://juejin.im/post/5ab20c58f265da23a228fe0f文章来源地址https://www.toymoban.com/news/detail-711249.html







到了这里,关于前端异步技术之Promise的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java前端技术栈】Promise

    1. 传统的 Ajax 异步调用在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的Callback Hell 2. 为了解决上述的问题, Promise对象 应运而生,在 EMCAScript 2015当中已经成为标准 3. Promise 是 异步编程的一种解决方案 。 4. 从语法上说,Promise 是一个对象,

    2024年02月20日
    浏览(75)
  • 前端技术栈 - ES6 - Promise -模块化编程

    ECMAScript 6.0(简称ES6)是JavaScript语言的下一代标准, 2015年6月发布. ES6设计目标: 达到JavaScript语言可以用来编写复杂的大型程序, 成为企业级开发语言. ECMAScript和JavaScript的关系就: ECMAScript是JavaScript的规范/规则, JavaScript是ECMAScript的一种实现. let.html +与,的区别 let_detail.html 细节1. l

    2024年02月11日
    浏览(297)
  • 【异步系列三】10道 Promise 面试题彻底理解 Promise 异步执行顺序

    上一篇文章详细说明了关于 Promise 的概念以及执行顺序,Promise 作为 JavaScript 中的关键特性,无论是在日常工作中还是面试中,我们都必须掌握它。 前段时间在网上看到了一些关于 Promise 的面试题,质量很好,在这里整理到下面,并加上我一些自己的见解,欢迎斧正! 1. 同步

    2024年02月09日
    浏览(47)
  • 异步同步化( Promise 详解)

    ES 6 Promise的用法 一 、为什么要使用Promise “ 回调地狱 ”这个词,不知道大家听过没有,就是异步调用 获取到结果 后, 为下一个异步函数提供 参数 ,所以就会一层一层的出现回调里面 嵌入回调,导致层次很深,代码维护起来特别的复杂,看一下下面的小案例大家就知道什

    2024年02月16日
    浏览(47)
  • JS中的异步编程与Promise

    在了解JavaScript的异步机制之前,我们首先需要理解JavaScript是一种单线程语言。单线程就意味着所有的任务需要按照顺序一次执行,如果前一个任务没有完成,后一个任务就无法开始。这个特性在执行大量或耗时任务时可能会导致阻塞或者界面卡死,这显然是不可取的。 为了

    2024年02月08日
    浏览(50)
  • promise及异步编程async await

    ECMAScript 6 新增了正式的 Promise(期约)引用类型,支持优雅地定义和组织异步逻辑。接下来几个版本增加了使用 async 和 await 定义异步函数的机制 JavaScript 是单线程事件循环模型。异步行为是为了优化因计算量大而时间长的操作,只要你不想为等待某个异步操作而阻塞

    2024年02月04日
    浏览(42)
  • 微信小程序异步请求数据promise方法

    在小程序中可以直接使用promise,我们需要做的就是在A函数中返回一个promise,在返回的promise中再进行获取数据的操作,把成功获取到的数据传入resolve中,把失败的结果传入reject,然后在B函数中调用A函数,调用后再使用.then 和 .catch 分别对成功和失败的结果进行处理

    2024年02月06日
    浏览(46)
  • [javascript核心-04]彻底弄懂Promise异步编程

    本文github地址:JavaScript_Interview_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士 1.1. 快速上手 01快手上手.js 02.若传入的是另一个promise对象,则状态由传入的promise对象决定 03.若传入了一个实现了 then 方法的对象,则执行该then方法且由此方法

    2024年02月08日
    浏览(40)
  • JavaScript 异步解决方案 Promise 全解析(转载)

    Promise 是一个 JS 的异步编程解决方案,解决了传统异步编程回调地狱的问题。 从语义上来说: Promise 是一个向外部传达异步编程操作消息的对象。 JS里一个promise可以有以下几种基本状态: nothing happened yet \\\"locked in\\\" to another promise fulfilled rejected 其中{1,2}为 pending ,{3,4}为 settl

    2024年02月08日
    浏览(61)
  • 什么是Promise对象?它的状态有哪些?如何使用Promise处理异步操作?以及 async、await

    前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一

    2024年02月11日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包