前端异步技术之promise(代码片段)

ccylovehs ccylovehs     2023-03-09     111

关键词:

前言

从事前端的朋友或多或少的接触过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

技术图片

2.3.4

技术图片

经过改正测试成功

技术图片

后记

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

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

 

技术图片

参考资料

https://promisesaplus.com/

http://liubin.org/promises-book

https://juejin.im/post/5ab20c58f265da23a228fe0f







es6——异步操作之promise(代码片段)

基本概念:  Promise:是ES6中新增的异步编程解决方案,提现在代码中他是一个对象可以通过Promise构造函数来实例化。  -newPromise(cb)===>实例的基本使用,PendingResolvedRejected >两个原型方法:  -Promise.prototype.then()-Prom... 查看详情

es6之promise简单理解及使用(代码片段)

promise1.promise是解决异步的一种方案,也就是让promise帮我们去处理异步,最终promise会返回异步处理的结果。2.有了promise之后,让异步处理更加灵活,还能够解决之前的回调地狱的问题。promise的使用我们需要用promise帮我们处理异... 查看详情

异步编程解决方案之promise/deferred(代码片段)

Promise三种状态:未完成、完成态、失败态varevents=require(‘events‘);varutil=require(‘util‘);varEventEmitter=events.EventEmitter;varPromise=function()EventEmitter.call(this);util.inherits(Promise,EventEmitter);Promis 查看详情

ecmascript6_异步编程之promise(代码片段)

Promise对象异步编程方案,已同步的方式表达异步的代码,解决回调地狱的问题比传统的解决方案——回调函数和事件——更合理和更强大是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的... 查看详情

#打卡不停更#三方库移植之napi开发[4]异步调用:callback&promise(代码片段)

...CPU密集型任务需要异步处理。NAPI支持异步模型,提供了Promise、Callback2种方式。往期回顾:三方库移植之NAPI开发[1]—HelloOpenHarmonyNAPI三方库移植之NAPI开发[2]C/C++与JS的数据类型转换三方库移植之NAPI 查看详情

vue之前后端交互(代码片段)

...码需要嵌套JS中常见的异步调用定时任务ajax事件函数二、promise(类型是构造函数)主要解决异步深层嵌套的问题(回调地狱)promise提供了简洁的API,使得异步操作更加容易2.1Promise的基本用法<scripttype="text/javascript">/*1.Promise... 查看详情

web前端练习19----es6新语法6,异步任务promise(代码片段)

百度搜索 mdn promise https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/PromisePromise基本用法,模拟请求数据functionmyAsyncTask(time)varpromise1=newPromise(function(success,f 查看详情

手写promise(代码片段)

...而言就显得尤为重要,其中在面试中被问道最多的就是对Promise方法的掌握情况,本章将和大家一起分析和完成一个Promise方法,希望对你的学习有一定的帮助。了解Promise既然我们是要模仿ES6的Promise,那我们必然要知道这个方法... 查看详情

这次聊聊promise对象(代码片段)

...海量技术实践干货哦~本文由前端林子发表于云+社区专栏Promise是CommonJS提出的一种规范,在ES6中已经原生支持Promise对象,非ES6环境可以用Bluebird等库来支持。0.引入在js中任务的执行模型有两种:同步模式和异步模式。同步模式:... 查看详情

es6之promise用法详解(代码片段)

一前言本文主要对ES6的Promise进行一些入门级的介绍。要想学习一个知识点,肯定是从三个方面出发,what、why、how。下面就跟着我一步步学习吧~二什么是Promise首先是what。那么什么是Promise呢? 以下是MDN对Promise的定义ThePromiseo... 查看详情

javascript系列之es6篇(代码片段)

八,Promise异步1,Promise简介(1)含义:promise是ES6引出的新的异步编程的解决方案,语法上promise是一个构造函数,用来封装异步操作并且可以获取其成功或失败的结果。2,简单的promise用例constp=n... 查看详情

[前端学习]promise对象一网打尽(代码片段)

文章目录Promise.prototype.finally()Promise.all()Promise.race()Promise.allSettled()Promise.any()Promise.resolve()Promise.reject()Promise.try()Promise的含义Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大 查看详情

[前端学习]promise对象一网打尽(代码片段)

文章目录Promise.prototype.finally()Promise.all()Promise.race()Promise.allSettled()Promise.any()Promise.resolve()Promise.reject()Promise.try()Promise的含义Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大 查看详情

关于promise(代码片段)

...都完成后才能执行后续的任务,无法实现并行节约时间2.PromisePromise本意是承诺,在程序中的意思就是承诺我过一段时间后会给你一个结果。什么时候会用到过一段时间?答案是异步操作,异步是指可能比较长时间才有结果的 查看详情

前端异步流程工具(代码片段)

前端异步流程工具传统:回调函数流行:Promise*最流行constp1=newPromise(function(resolve,reject)resolve(‘任务一‘)).then(function(data)console.log(data))constp2=newPromise(function(resolve,reject)setTimeout(function()resol 查看详情

promise.all的异常处理,前端开发者需了解(代码片段)

文章目录Promise.all的基本使用问题:需自己catch返回失败的值Promise.allSettled方法背景咱们在开发中,大多数时间都是一个异步操作一个异步操作去执行的,但是有一些特殊情况,需要一股脑去执行多个异步操作,比... 查看详情

关于promise详解(代码片段)

...作都完成后才能执行后续的任务,无法实现并行节约时间PromisePromise本意是承诺,在程序中的意思就是承诺我过一段时间后会给你一个结果。什么时候会用到过一段时间?答案是异步操作,异步是指可能比较长时间才有结果的才... 查看详情

promise学习笔记(代码片段)

注:笔记来自于视频尚硅谷Web前端Promise教程从入门到精通注:如果是初学仅需要学会Promise的基本使用即可,不要陷入要自己实现手写Promise中。Promise的理解和使用Promise是什么Promise是一门新的技术,ES6技术规范。P... 查看详情