精华内容
下载资源
问答
  • 在引用axios.js前先引用bluebird.js 转载于:https://www.cnblogs.com/Kuais/p/9121210.html

     

    在引用axios.js前先引用 bluebird.js 

     

    转载于:https://www.cnblogs.com/Kuais/p/9121210.html

    展开全文
  • https://github.com/axios/axios/blob/master/UPGRADE_GUIDE.md#es6-promise-polyfill https://stackoverflow.com/questions/35769777/axios-ie-promise-doesnt-work https://sharepoint.stackexchange.com/qu...

    參考

    https://github.com/axios/axios/blob/master/UPGRADE_GUIDE.md#es6-promise-polyfill

    https://stackoverflow.com/questions/35769777/axios-ie-promise-doesnt-work

    https://sharepoint.stackexchange.com/questions/249711/axios-sharepoint-error-in-ie-11-but-not-chrome

     

     

    也可以

    // 将Promise抛出为全局对象

    window.Promise = Promise

    原理:当babel检查到jsPromise时,transform-runtime会将Promise做转换,然后将其抛出为全局对象即可达到跟babel-polyfill一样的效果。

    展开全文
  • Promise-land和Stream-land之间缺少的链接。 目录 用法 这个轻量级的库仅包含一些简单的函数。 所有功能都位于React\Promise\Stream命名空间下。 以下示例假定您使用与此类似的导入语句: use React \ Promise ...
  • promise

    2018-04-08 02:47:36
    一、promise是什么?有什么特点? Promise 是异步编程的一种解决方案,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作...

    一、promise是什么?有什么特点?

    Promise 是异步编程的一种解决方案,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。同时从代码上讲Promise是一个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等方法

    特点:

    • **对象的状态不受外界影响。**Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    • **一旦状态改变,就不会再变,任何时候都可以得到这个结果。**Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两个可能发生一个则不能再去改变。

    ####二、常见异步编程的方案 在js的异步那篇文章中有提到很多的方式可以查看https://www.jianshu.com/p/1fbb9789cde3这里重点讲一下callback,promise的起源。下面我们用callback实现一个读取文件a和b之后打印出他们的内容的功能。(备注:下面的代码可以直接在vscode中安装 Code Runner 插件来run)

    const fs = require('fs')
    fs.readFile('a.txt', 'utf8', funcrion (err, data) {
        fs.readFile('b.txt', 'utf8', funcrion (err, data) {
            console.log(data)
        })
    })
    复制代码

    问题:

    1. 嵌套(回调地狱)的问题
    2. 无法支持多个文件无顺序读取返回结果

    怎么办呢?我们想到了高阶函数

    const fs = require('fs')
    // 缓存函数,当满足条件的时候去执行
    function after (times, callback) {
        const arr = []
        return function (data) {
            arr.push(data)
            if (--times === 0) {
                callback(arr)
            }
        }
    }
    let out = after(2, function (arr) {
        console.log(arr)
    })
    fs.readFile('a.txt', 'utf8', funcrion (err, data) {
        out(data)
    })
    fs.readFile('b.txt', 'utf8', funcrion (err, data) {
        out(data)
    })
    复制代码

    到这里我们终于完成了我们想要的结果,但是作为一个有追求的程序员怎么能满足于这样的写法呢?终于promise诞生了

    ####三、promise的基本用法

    1. ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
    // resolve 将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
    // reject 将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
    const promise = new Promise(function(resolve, reject) {
      // do something
      if (/* 异步操作成功 */){
        resolve(value)
      } else {
        reject(error)
      }
    })
    复制代码
    1. Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    })
    复制代码

    下面我们用promise同样实现一个读取文件a和b之后打印出他们的内容的功能

    let fs = require('fs')
    function read(url) {
        return new Promise(function (resolve, reject) {
            fs.readFile(url, 'utf8', function (err, data) {
                if (err) {
                    reject(err)
                } else {
                    resolve(data)
                }
            })
        })
    }
    read('a.txt').then((data) => {
        return read(data)
    }).then((data) => {
        console.log(data)
    }).catch((err) => {
        console.log(err)
    })
    复制代码

    好了这样我们的代码是不是就好看一些了呢?终于从回调地狱走出来了。那我们来看看它还支持了什么

    1. Promise.prototype.catch() : 捕捉错误 (常用方法不做赘述)
    2. Promise.all():将多个 Promise 实例,包装成一个新的 Promise 实例。一起读多个文件,返回的依旧是一个Promise
    // p1, p2, p3均为promise的实例。
    // p的状态由p1、p2、p3决定,分成两种情况
    //(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    //(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
    
    const p = Promise.all([p1, p2, p3])
    复制代码
    1. Promise.race():将多个 Promise 实例,包装成一个新的 Promise 实例,但只要有一个返回状态就结束。赛跑制度,以第一名为结果
    2. Promise.resolve():将现有对象转为 Promise 对象
    3. Promise.reject():返回一个新的 Promise 实例,该实例的状态为rejected。就是说不管promise中的then走向成功还是失败都将返回值作为下一次then的结果

    四、promise规范和要求

    • fulfill:指一个 promise 成功时进行的一系列操作,如状态的改变、回调的执行。规范中用 fulfill 来表示解决,在后世的 promise 实现多以 resolve 来指代之
    • reject:指一个 promise 失败时进行的一系列操作
    • value:promise 被解决时传递给解决回调的值
    • reason:在 promise 被拒绝时传递给拒绝回调的值

    要求:

    1. 一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)
      • 等待态:可以变更为执行态或拒绝态
      • 执行态:不能再去改变状态,必须包含一个最终值(value)
      • 拒绝态:不能再去改变状态,必须包含一个拒绝的原因(reason)
    2. 一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因。onFulfilled 和 onRejected 均为可选参数但必须被作为函数调用(即没有 this 值)
    3. Promise 解决过程 是一个抽象的操作,其需输入一个 promise 和一个值,我们表示为 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise

    五、实现

    function Promise (executer) {
        const _this = this
        _this.status = 'padding' // 当前状态
        _this.value = null // 成功后的值
        _this.reason = null // 失败的原因
        _this.onResolved = [] // 成功的回调函数的的数组
        _this.onRejected = [] // 失败的回调函数的的数组
        function resolve (value) { // 成功的状态
            if (_this.status === 'padding') {
                _this.status = 'resolved'
                _this.value = value
                _this.onResolved.forEach(function (fn) {
                    fn()
                })
            }
        }
        function reject (reason) { // 失败的状态
            if (_this.status === 'padding') {
                _this.status = 'rejected'
                _this.reason = reason
                _this.onRejected.forEach(function (fn) {
                    fn()
                })
            }
        }
        // 如果有异常直接走到reject
        try {
            executer(resolve, reject)
        } catch(e) {
            reject(e)
        }
    }
    
    // 用来统一处理返回
    resolvePrmoise (np, x, resolve, reject) {
        // 先处理错误
        if (np === x) { // 如果新的promise和返回值一样说明发生了循环引用
            // 报类型错误
            return reject(new TypeError('循环引用'))
        }
        // 如果x是一个promise则需要获取他的结果
        if (x !== null && (typeof x === 'object' || typeof x === 'function') ) {
            // 查看对象中是否有then来确认是否为promise
            let called = false
            try {
                let then = x.then
                if (typeof then !== 'function') {
                    resolve(x)
                } else { // 确认是一个promise
                    then.call(x, function (data) {
                        if (called) { rteurn }
                        called = true
                        // 允许递归多个promise,所以data可能还是一个promise
                        resolvePrmoise(np, data, resolve, reject)
                    }, function (err) {
                        if (called) { rteurn }
                        called = true
                        reject(err)
                    })
                }
            } catch (e) {
                if (called) { rteurn }
                called = true
                reject(e)
            }
        } else { // 说明是一个普通值
            resolve(x)
        }
    }
    Promise.prototype.then = function (onFulfilled, onRejected) {
        // 利用默认值规避then里面不传递onFulfilled, onRejected的问题
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) { return value }
        onRejected = typeof onRejected === 'function' ? onRejected : function (err) { throw err }
    
        const _this = this
        let newpromise
        if (_this.status === 'resolved') {
            newpromise = new Promise(function (resolve, reject) {
                setTimeout(function () {
                    try {
                        let x = onFulfilled(_this.value)
                        resolvePrmoise(newpromise, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            })
        }
        if (_this.status === 'rejected') {
            newpromise = new Promise(function (resolve, reject) {
                setTimeout(function () {
                    try {
                        let x = onRejected(_this.reason)
                        resolvePrmoise(newpromise, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            })
        }
        if (_this.status === 'pedding') {
            newpromise = new Promise(function (resolve, reject) {
                _this.onResolved.push(function () {
                    setTimeout(function () {
                        try {
                            let x = onFulfilled(_this.value)
                            resolvePrmoise(newpromise, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
                _this.onRejected.push(function () {
                    setTimeout(function () {
                        try {
                            let x = onRejected(_this.reason)
                            resolvePrmoise(newpromise, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
            })
        }
        return newpromise
    }
    // 通过返回一个Promise的实例来实现使用的时候减少new Promise的返回
    Promise.defer = Promis.edefferred = function () {
        let dfd = {}
        dfd.promise = new Promise(function (resolve, reject) {
            dfd.resolve = resolve
            dfd.reject = reject
        })
        return dfd
    }
    复制代码

    好了这个代码基本实现了我们的需求,那我们来测试一下吧。promise的测试库 promisees-aplus-tests

    npm install promisees-aplus-tests
    promisees-aplus-tests 文件名
    复制代码

    看起来一切都很好,根据上面的promise的方法知道它还支持几个方法,例如catch等,一个一个消灭

    1. catch
    Promise.prototype.catch = function (callback) {
        return this.then(null, callback)
    }
    复制代码
    1. Promise.all
    Promise.all = function (promises) {
        // promises是一个数组
        let arr = [] // 最终的返回值
        let i = 0 // 表示成功了多少次
        function processData (index, y) {
            arr[index] = y
            if (++i === promises.length) {
                resolve(arr)
            }
        }
        return new Promise(function(resolve, reject) {
            for(let i = 0; i < promises.length; i++) {
                promises[i].then(function (y) {
                    processData(i, y)
                }, reject)
            }
        })
    }
    复制代码
    1. Promise.race
    Promise.race = function (promises) {
        return new Promise(function(resolve, reject) {
            const len = promises.length
            for (let i = 0; i < len; i++) {
                promises[i].then(resolve, reject)
            }
        })
    }
    复制代码
    1. Promise.resolve
    Promise.resolve = function (value) {
        return new Promise(function(resolve, reject) {
            resolve(value)
        })
    }
    复制代码
    1. Promise.reject
    Promise.reject = function (reason) {
        return new Promise(function(resolve, reject) {
            reject(reason)
        })
    }
    复制代码

    六、拓展promise + generator + co

    generator是什么?

    Generator生成器函数也是异步的一个解决方案。生成器函数顾名思义,它是一个生成器,它也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器Iterator对象,我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。

    generator 要求和特点

    • generator 函数需要用*来标识,用yield来暂停
    • 它会将函数分割出很多个小块,调用一次next就会继续往下执行
    • 返回结果是一个迭代器(所以调用是不会执行的) 含有一个next方法
    • yield后面跟着的就是value的值
    • yield前面是我们当前调用next传进来的值
    • 第一次next的传值是无效的

    demo

    function *read () {
        console.log(1)
        let a = yield 'hello'
        console.log(a) // undefined
        let b = yield 'word'
        console.log(b)
        return b
    }
    let it = read()
    console.log(it.next()) // {value: 'hello', done: false}
    console.log(it.next()) // {value: 'word', done: false}
    复制代码

    为啥 a 会是 undefined ?图解一下这个代码

    1. 第一步let it = read()只会返回一个迭代器,所以不会执行
    2. 第一次执行it.next()之后红色的区域执行,然后因为yield暂停了,注意这里不是赋值
    3. 当再次执行next黄色区域执行,而因为你并没有传递参数所以a就是undefined
    4. 同理继续执行b也是一样的

    那根据这个顺序,我们试试传递参数

    function *read () {
        console.log(1)
        let a = yield 'hello'
        console.log(a) // 100
        let b = yield 'word'
        console.log(b)
        return b
    }
    let it = read()
    console.log(it.next()) // {value: 'hello', done: false}
    console.log(it.next(100)) // {value: 'word', done: false}
    console.log(it.next(200)) // {value: '!!', done: false}
    复制代码

    果然!奇葩函数啊!这个奇葩一般怎么玩呢?搭配promise

    let bluebird = require('bluebird')
    let fs = require('fs')
    let read = bluebird.promiseify(fs.readFile)
    function *read () {
        let contentA = yield read('a.txt', 'utf8')
        let contentB = yield read(contentA, 'utf8')
        return contentB
    }
    // 调用
    let it = read()
    it.next().value.then(function (data) { // b.txt
        it.next(data).value.then(function (data) {
            console.log(it.next(data).value)
        })
    })
    复制代码

    好了,感觉上面的读取很爽,但是这个调用。。。。不能忍!!!这个时候就该co出场了,它是干啥呢?说白了它就是用co来自动迭代 迭代器函数的

    // 用 npm install co 安装co
    let co = require('co')
    co(read()).then(function(data){
        console.log(data)
    })
    复制代码

    这个调用是不是就好很多了,思考一下co的实现,就是帮我们递归调用方法执行然后返回一个promise

    function co (it) {
        return new Promise(function (resolve, reject) {
            function next (json) {
                let {value, done} = it.next(json)
                if (!done) {
                    value.then(function (data) {
                        next(data)
                    }, reject)
                } else {
                    resolve(value)
                }
            }
            next()
        })
    }
    复制代码

    ####七、参考文档

    • Promise 对象 http://es6.ruanyifeng.com/#docs/promise
    • promise a+ 规范 https://promisesaplus.com/

    转载于:https://juejin.im/post/5ac982abf265da2385331ffd

    展开全文
  • Promise

    2019-09-29 11:26:45
    复制代码这里需要注意的是,当我们new Promise 的时候Promise里的函数会直接执行。所以如果你想定义一个Promise以待后用,比如axios封装,需要用函数包装。比如这样: function myPromise() { return new Promise...
    众所周知,js是单线程异步机制的。这样就会导致很多异步处理会嵌套很多的回调函数,最为常见的就是ajax请求,我们需要等请求结果返回后再进行某些操作。如: function success(data, status) { console.log(data) } function fail(err, status) { console.log(err) } ajax({ url: myUrl, type: 'get', dataType: 'json', timeout: 1000, success: success(data, status), fail: fail(err, status) }) 复制代码 乍一看还行啊,不够绝望啊,让绝望来的更猛烈一些吧!那么试想一下,如果还有多个请求依赖于上一个请求的返回值呢?五个?六个?代码就会变得非常冗余和不易维护。这种现象,我们一般亲切地称它为‘回调地狱’。现在解决回调地狱的手段有很多,比如非常方便的async/await、Promise等。 我们现在要讲的是Promise。在如今的前端面试中,Promise简直是考点般的存在啊,十个有九个会问。那么我们如何真正的弄懂Promise呢?俗话说的好,‘想要了解它,先要接近它,再慢慢地实现它’。自己实现一个Promise,不就什么都懂了。 其实网络上关于Promise的文章有很多,我也查阅了一些相关文章,文末有给出相关原文链接。所以本文侧重点是我在实现Promise过程中的思路以及个人的一些理解,有感兴趣的小伙伴可以一起交流。 如果用promise实现上面的ajax,大概是这个效果: ajax().success().fail(); 复制代码何为 Promise 那么什么是Promise呢? Promise是为了解决异步编程的弊端,使你的代码更有条理、更清晰、更易维护。 Promise是一个构造函数(或者类),接受一个函数作为参数,该函数接受resolve,reject两个参数。 它的内部有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),其中pending可以转化为fulfilled或者和rejected,但是不能逆向转化,成功和失败也不能相互转化。 value、reason成功的参数和失败的错误信息。 then方法,实现链式调用,类似于jq。 基本用法: let getInfo = new Promise((resolve, reject) => { setTimeout(_ => { let ran = Math.random(); console.log(ran); if (ran > 0.5) { resolve('success'); } else { reject('fail'); } }, 200); }); getInfo.then(r => { return r + ' ----> Vchat'; }).then(r => { console.log(r); }).catch(err => { console.log(err); }) // ran > 0.5输出 success ----> Vchat // ran <= 0.5输出 fail 复制代码先定个小目标,然后一步步实现它。 构建Promise 基础构造 首先需要了解一下基本原理。我第一次接触Promise的时候,还很懵懂(捂脸)。那会只知道这么写,不知道到底是个什么流程走向。下面,我们来看看最基本的实现: function Promise(Fn){ let resolveCall = function() {console.log('我是默认的');}; // 定义为函数是为了防止没有then方法时报错 this.then = (onFulfilled) => { resolveCall = onFulfilled; }; function resolve(v){ // 将resolve的参数传给then中的回调 resolveCall(v); } Fn(resolve); } new Promise((resolve, reject) => { setTimeout(_ => { resolve('success'); }, 200) }).then(r => { console.log(r); }); // success 复制代码这里需要注意的是,当我们new Promise 的时候Promise里的函数会直接执行。所以如果你想定义一个Promise以待后用,比如axios封装,需要用函数包装。比如这样: function myPromise() { return new Promise((resolve, reject) => { setTimeout(_ => { resolve('success'); }, 200) }) } // myPromise().then() 复制代码再回到上面,在new Promise 的时候会立即执行fn,遇到异步方法,于是先执行then中的方法,将 onFulfilled 存储到 resolveCall 中。异步时间到了后,执行 resolve,从而执行 resolveCall即储存的then方法。这是输出的是我们传入的‘success’ 这里会有一个问题,如果 Promise 接受的方法不是异步的,则会导致 resolve 比 then 方法先执行。而此时 resolveCall 还没有被赋值,得不到我们想要的结果。所以要给resolve加上异步操作,从而保证then方法先执行。 // 直接resolve new Promise((resolve, reject) => { resolve('success'); }).then(r => { console.log(r); // 输出为 ‘我是默认的’,因为此时then方法还没有,then方法的回调没有赋值给resolveCall,执行的是默认定义的function() {}。 }); // 加上异步处理,保证then方法先执行 function resolve(v){ setTimeout(_ => { resolveCall(v); }) } 复制代码 增加链式调用 链式调用是Promise非常重要的一个特征,但是上面写的那个函数显然是不支持链式调用的,所以我们需要进行处理,在每一个then方法中return一下this。 function Promise(Fn){ this.resolves = []; // 方便存储onFulfilled this.then = (onFulfilled) => { this.resolves.push(onFulfilled); return this; }; let resolve = (value) =>{ // 改用箭头函数,这样不用担心this指针问题 setTimeout(_ => { this.resolves.forEach(fn => fn(value)); }); }; Fn(resolve); } 复制代码可以看到,这里将接收then回调的方法改为了Promise的属性resolves,而且是数组。这是因为如果有多个then,依次push到数组的方式才能存储,否则后面的then会将之前保存的覆盖掉。这样等到resolve被调用的时候,依次执行resolves中的函数就可以了。这样可以进行简单的链式调用。 new Promise((resolve, reject) => { resolve('success'); }).then(r => { console.log(r); // success }).then(r => { console.log(r); // success }); 复制代码但是我们会有这样的需求, 某一个then链想自己return一个参数供后面的then使用,如: then(r => { console.log(r); return r + ' ---> Vchat'; }).then(); 复制代码要做到这一步,需要再加一个处理。 let resolve = (value) =>{ setTimeout(_ => { // 每次执行then的回调时判断一下是否有返回值,有的话更新value this.resolves.forEach(fn => value = fn(value) || value); }); }; 复制代码 增加状态 我们在文章开始说了Promise的三种状态以及成功和失败的参数,现在我们需要体现在自己写的实例里面。 function Promise(Fn){ this.resolves = []; this.status = 'PENDING'; // 初始为'PENDING'状态 this.value; this.then = (onFulfilled) => { if (this.status === 'PENDING') { // 如果是'PENDING',则储存到数组中 this.resolves.push(onFulfilled); } else if (this.status === 'FULFILLED') { // 如果是'FULFILLED',则立即执行回调 console.log('isFULFILLED'); onFulfilled(this.value); } return this; }; let resolve = (value) =>{ if (this.status === 'PENDING') { // 'PENDING' 状态才执行resolve操作 setTimeout(_ => { //状态转换为FULFILLED //执行then时保存到resolves里的回调 //如果回调有返回值,更新当前value this.status = 'FULFILLED'; this.resolves.forEach(fn => value = fn(value) || value); this.value = value; }); } }; Fn(resolve); } 复制代码这里可能会有同学觉得困惑,我们通过一个例子来说明增加的这些处理到底有什么用。 let getInfo = new Promise((resolve, reject) => { resolve('success'); }).then(_ => { console.log('hahah'); }); setTimeout(_ => { getInfor.then(r => { console.log(r); // success }) }, 200); 复制代码在resolve函数中,判断了'PENDING' 状态才执行setTimeout方法,并且在执行时更改了状态为'FULFILLED'。这时,如果运行这个例子,只会输出一个‘success’,因为接下来的异步方法调用时状态已经被改为‘FULFILLED’,所以不会再次执行。 这种情况要想它可以执行,就需要用到then方法里的判断,如果状态是'FULFILLED',则立即执行回调。此时的传参是在resolve执行时保存的this.value。这样就符合Promise的状态原则,PENDING不可逆,FULFILLED和REJECTED不能相互转化。 增加失败处理 可能有同学发现我一直没有处理reject,不用着急。reject和resolve流程是一样的,需要一个reason做为失败的信息返回。在链式调用中,只要有一处出现了reject,后续的resolve都不应该执行,而是直接返回reject。 this.reason; this.rejects = []; // 接收失败的onRejected函数 if (this.status === 'PENDING') { this.rejects.push(onRejected); } // 如果状态是'REJECTED',则立即执行onRejected。 if (this.status === 'REJECTED') { onRejected(this.reason); } // reject方法 let reject = (reason) =>{ if (this.status === 'PENDING') { setTimeout(_ => { //状态转换为REJECTED //执行then时保存到rejects里的回调 //如果回调有返回值,更新当前reason this.status = 'REJECTED'; this.rejects.forEach(fn => reason = fn(reason) || reason); this.reason = reason; }); } }; // 执行Fn出错直接reject try { Fn(resolve, reject); } catch(err) { reject(err); } 复制代码在执行储存then中的回调函数那一步有一个细节一直没有处理,那就是判断是否有onFulfilled或者onRejected方法,因为是允许不要其中一个的。现在如果then中缺少某个回调,会直接push进undefined,如果执行的话就会出错,所以要先判断一下是否是函数。 this.then = (onFulfilled, onRejected) => { // 判断是否是函数,是函数则执行 function success (value) { return typeof onFulfilled === 'function' && onFulfilled(value) || value; } function erro (reason) { return typeof onRejected === 'function' && onRejected(reason) || reason; } // 下面的处理也要换成新定义的函数 if (this.status === 'PENDING') { this.resolves.push(success); this.rejects.push(erro); } else if (this.status === 'FULFILLED') { success(this.value); } else if (this.status === 'REJECTED') { erro(this.reason); } return this; }; 复制代码因为reject回调执行时和resolve基本一样,所以稍微优化一下部分代码。 if(this.status === 'PENDING') { let transition = (status, val) => { setTimeout(_ => { this.status = status; let f = status === 'FULFILLED', queue = this[f ? 'resolves' : 'rejects']; queue.forEach(fn => val = fn(val) || val); this[f ? 'value' : 'reason'] = val; }); }; function resolve(value) { transition('FULFILLED', value); } function reject(reason) { transition('REJECTED', reason); } } 复制代码 串行 Promise 假设有多个ajax请求串联调用,即下一个需要上一个的返回值作为参数,并且要return一个新的Promise捕捉错误。这样我们现在的写法就不能实现了。 我的理解是之前的then返回的一直是this,但是如果某一个then方法出错了,就无法跳出循环、抛出异常。而且原则上一个Promise,只要状态改变成‘FULFILLED’或者‘REJECTED’就不允许再次改变。 之前的例子可以执行是因为没有在then中做异常的处理,即没有reject,只是传递了数据。所以如果要做到每一步都可以独立的抛出异常,从而终止后面的方法执行,还需要再次改造,我们需要每个then方法中return一个新的Promise。 // 把then方法放到原型上,这样在new一个新的Promise时会去引用prototype的then方法,而不是再复制一份。 Promise.prototype.then = function(onFulfilled, onRejected) { let promise = this; return new Promise((resolve, reject) => { function success (value) { let val = typeof onFulfilled === 'function' && onFulfilled(value) || value; resolve(val); // 执行完这个then方法的onFulfilled以后,resolve下一个then方法 } function erro (reason) { let rea = typeof onRejected === 'function' && onRejected(reason) || reason; reject(rea); // 同resolve } if (promise.status === 'PENDING') { promise.resolves.push(success); promise.rejects.push(erro); } else if (promise.status === 'FULFILLED') { success(promise.value); } else if (promise.status === 'REJECTED') { erro(promise.reason); } }); }; 复制代码在成功的函数中还需要做一个处理,用以支持在then的回调函数(onFulfilled)中return的Promise。如果onFulfilled方法return的是一个Promise,则直接执行它的then方法。如果成功了,就继续执行后面的then链,失败了直接调用reject。 function success(value) { let val = typeof onFulfilled === 'function' && onFulfilled(value) || value; if(val && typeof val['then'] === 'function'){ // 判断是否有then方法 val.then(function(value){ // 如果返回的是Promise 则直接执行得到结果后再调用后面的then方法 resolve(value); },function(reason){ reject(reason); }); }else{ resolve(val); } } 复制代码找个例子测试一下 function getInfo(success, fail) { return new Promise((resolve, reject) => { setTimeout(_ => { let ran = Math.random(); console.log(success, ran); if (ran > 0.5) { resolve(success); } else { reject(fail); } }, 200); }) } getInfo('Vchat', 'fail').then(res => { console.log(res); return getInfo('可以线上预览了', 'erro'); }, rej => { console.log(rej); }).then(res => { console.log(res); }, rej => { console.log(rej); }); // 输出 // Vchat 0.8914818954810422 // Vchat // 可以线上预览了 0.03702367800412443 // erro 复制代码 总结 到这里,Promise的主要功能基本上都实现了。但是还有很多实用的扩展,我们也可以添加。 比如 catch可以看做then的一个语法糖,只有onRejected回调的then方法。 Promise.prototype.catch = function(onRejected){ return this.then(null, onRejected); } 复制代码还有很多Promise的方法,比如.all、.race 等等,感兴趣的小伙伴可以自己实现一下。 作者:江三疯 链接:https://juejin.im/post/5c179aad5188256d9832fb61

    转载于:https://www.cnblogs.com/kkdn/p/10143854.html

    展开全文
  • 首先是采用vue渲染的页面在IE中直接不显示,控制台报错SCRIPT1003: 缺少 ‘:’ 原因: 点击找到对应的行,原来是methods里面声明的方法,es6标准的省略“function”的写法,IE不兼容; 解决方法: 将省略的...
  • promise原理

    2019-04-25 11:48:00
    Promise 对象是一个返回值的代理,这个返回值在promise对象创建时未必已知。它允许你为异步操作的成功或失败指定处理方法。 这使得异步方法可以像同步方法那样返回值:异步方法会返回一个包含了原返回值的...
  • Fetch与Promise

    万次阅读 2018-03-16 17:31:48
    本文不是 Fetch API 科普贴,其实是讲异步处理和 Promise 的。Fetch API 很简单,看文档很快就学会了。推荐 MDN Fetch 教程 和 万能的 WHATWG Fetch 规范由于 Fetch API 是基于 Promise 设计,有必要先学习一下 ...
  • es6 Promise对象

    2021-04-27 18:52:29
    Promise对象promise的含义基本用法 promise的含义 promise是异步编程的一种解决方案,比传统的方法——回调函数和事件,更加合理和强大。promise是一个容器,里面保存着未来才会结束事件的结果(通常是一个异步操作...
  • js--promise

    2021-10-02 16:39:03
    promise Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。 一个 Promise 必然处于以下几种状态之一: 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。...当 .then() 中缺少能够返回 p
  • Promise应用场景

    千次阅读 2019-05-28 01:51:40
    众所周知,Promise是为了解决回调地狱问题而产生的,其主要应用于向发服务端发起请求等异步操。那么,除了异步请求还有其他场景适合使用 Promise 吗?下面我们来共同探讨下。 并发执行的任务 Promise除了用于异步...
  • catch() 方法返回一个Promise,并且只处理拒绝(rejected )的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部调用obj.then(undefined, ...
  • Promise学习心得

    2019-01-09 17:32:38
    为什么要使用Promise Promise是一个代表了异步操作最终完成或者失败的对象 主要解决回调地狱 有助于以一种有效的方式对异步进行分组 Promises/A+规范早已经有其他语言实现 什么是Promise Promise 对象是一个代理...
  • js promise chain

    2019-09-22 07:21:24
    js promise chain 新的标准里增加了原生的Promise。 这里只讨论链式使用的情况,思考一下其中的细节部分。 一,关于 then() 和 catch() 的复习 then() 和 catch() 的参数里可以放置 callback 函数...
  • es6之Promise

    2019-08-08 22:15:30
    在说promise之前有一些背景了解一下 jQuery从v1.5之后的版本都提供了Deferred方法,$.Deferred()会返回一个对象,包含有resolve、reject和done、fail、then方法; resolve、reject是主动触发改变状态的函数; ...
  • Promise 对象方法总结

    2020-12-18 20:54:37
    ECMAscript 6 原生提供了 Promise 对象。 Promise Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息,是一套异步操作处理机制。 Promise对象解决回调地狱层层嵌套的问题。 通过then方法分别制定...
  • ES6之Promise对象

    2019-10-22 13:01:06
    在 ES6 中新增加了一种新的对象 —— Promise。 它的中文意思是 “承诺”,也就是答应别人的事就不会改变。而这个对象也如其名,一旦新建它就会立即执行,无法中途取消。 它从语法上来看,就是一个对象,它就是 ...
  • promise手写源码

    2020-05-27 17:46:57
    class PromiseNew{ constructor(fn){ this.satate="PENDING" this.doneList = [] this.failList = [] fn(this.resolve.bind(this) ,this.reject.bind(this)) //fn是外部函数,里面this已经改变,所以要绑定bind...
  • es6 Promise.prototype.catch()方法

    千次阅读 2018-01-27 22:26:48
    Promise.prototype.catch()方法 Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。 getJSON('/posts.json').then(function(posts) { // ...}).catch(function...
  • Promise对象探究

    2016-08-15 12:22:42
    我的简单理解是,Promise是JavaScript异步回调的解决方案之一,最大的优点是以链式调用的方式来消除Callback Hell的问题。二、用法1、运用一个Promise对象可以总结成两个步骤: 异步。决定回调的时机(when
  • ES6 之 Promise用法详解

    千次阅读 多人点赞 2020-11-20 17:22:57
    Promise 详解 源码解析
  • 不幸的是,仅原生的Promise缺少像这样的库所提供的许多强大的实用程序。 wise-promise扩展了提供相同功能的本机承诺。 安装 npm install --save wise-promise 用法 const Promise = require ( 'wise-promise' ) ; ...
  • 用于浏览器和节点的轻量级ES6 Promise polyfill。 严格遵守规范。 它是完美的polyfill IE或任何其他不支持本机Promise的浏览器。 有关Promises的API信息,请查阅本文。 它非常轻巧。 <1kb压缩 浏览器支持 IE8 ...
  • 当我们运行 Playground,编译器会报错: error: Promise.playground:41:9: error: use of unresolved identifier 'Promise' _ = Promise { string = "foo" } ^~~~~~~ 合理,因此需要定义 Promise 类: class ...
  • 点击上方三分钟学前端,关注公众号回复交流,加入前端编程面试算法每日一题群面试官也在看的前端面试资料引言本文从五个方面介绍 Promise.any :Promise.any 的作用Prom...
  • 手写一个简单的promise

    2020-10-22 13:07:10
    es6、es7现在是前端开发工作中,不可缺少的技能之一。 es6中Promise大家也用的越来越频繁。 下面是一个手写简单的Promise。 class PromiseFn { constructor(callback) { this.status = 'pendding' this.value = ...
  • 缺少场景支撑,对于新手而言,很难理解Promise的意义。 在《你不知道的JavaScript中》有个场景介绍得很形象: 我走到快餐店的柜台,点了一个芝士汉堡。我交给收银员1.47美元。通过下订单并付款,我已经发出了一个对...
  • 自己写一个Promise

    2020-09-17 17:38:36
    自己造轮子——在 ECMAScript5中自定义一个Promise,实现与ES6原生Promise一致的基本功能(测试中使用的箭头函数“=>”属于ES6标准)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,126
精华内容 1,650
关键字:

缺少promise