您的位置:新葡亰496net > 新葡亰官网 > 流程控制,异步流程控制

流程控制,异步流程控制

发布时间:2019-12-01 01:19编辑:新葡亰官网浏览(62)

    初探 Headless Chrome

    2017/06/15 · 底子技艺 · Chrome

    初稿出处: 饿了么前端   

    现代 JS 流程序调控制:从回调函数到 Promises 再到 Async/Await

    2018/09/03 · JavaScript · Promises

    原稿出处: Craig Buckler   译文出处:OFED   

    JavaScript 常常被认为是异步的。那象征什么?对开荒有哪些影响啊?近来,它又生出了哪些的变型?

    拜谒以下代码:

    result1 = doSomething1(); result2 = doSomething2(result1);

    1
    2
    result1 = doSomething1();
    result2 = doSomething2(result1);

    繁多编制程序语言同步实行每行代码。第意气风发行奉行完成再次回到一个结实。不论第大器晚成行代码施行多长期,唯有进行到位第二行代码才会进行。

    姚丽冰    学号:16050120089

    Promise 异步流程序调控制

    2017/10/04 · JavaScript · Promise

    原稿出处: 麦子谷   

    一· 什么是Promise

    什么是 Headless Chrome

    Headless Chrome 是 Chrome 浏览器的无分界面形态,能够在不张开浏览器的前提下,使用全数 Chrome 扶助的表征运转你的顺序。相比于今世浏览器,Headless Chrome 尤其惠及测量检验web 应用,获得网址的截图,做爬虫抓取新闻等。比较于出道较早的 PhantomJS,SlimerJS 等,Headless Chrome 则进一步接近浏览器情况。

    单线程管理程序

    JavaScript 是单线程的。当浏览器选项卡推行脚本时,别的全数操作都会终止。那是必然的,因为对页面 DOM 的改观不能够并发实践;二个线程
    重定向 U奥德赛L 的同期,另叁个线程正要增加子节点,这么做是危在旦夕的。

    顾客不轻巧觉察,因为管理程序会以组块的款型连忙试行。譬喻,JavaScript 检查测验到开关点击,运营计算,并更新 DOM。大器晚成旦成功,浏览器就足以轻便管理队列中的下一个类型。

    (附注: 别的语言举例 PHP 也是单线程,不过透过多线程的服务器举个例子 Apache 管理。同生机勃勃 PHP 页面同期提倡的七个央浼,能够运转五个线程运营,它们是相互隔开分离的 PHP 实例。)

    原作链接 zhuanlan.zhihu.com

    新葡亰496net 1前言

    新近单位在招前端,作为机关唯风度翩翩的前端,面试了比非常多应聘的同学,面试中有几个涉及 Promise 的叁个难点是:

    网页中预加载20张图纸能源,分步加载,叁回加载10张,若干遍成功,怎么调控图片央求的面世,怎么着感知当前异步诉求是或不是已成功?

    而是能一切答上的相当少,能够交给叁个回调 计数版本的,小编都认为合格了。那么接下去就联手来学学计算一下依照 Promise 来拍卖异步的两种办法。

    正文的例子是一个十二万分简化的三个卡通阅读器,用4张漫画图的加载来介绍异步管理区别措施的兑现和差异,以下是 HTML 代码:

    JavaScript

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Promise</title> <style> .pics{ width: 300px; margin: 0 auto; } .pics img{ display: block; width: 100%; } .loading{ text-align: center; font-size: 14px; color: #111; } </style> </head> <body> <div class="wrap"> <div class="loading">正在加载...</div> <div class="pics"> </div> </div> <script> </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Promise</title>
      <style>
        .pics{
          width: 300px;
          margin: 0 auto;
        }
        .pics img{
          display: block;
          width: 100%;
        }
        .loading{
          text-align: center;
          font-size: 14px;
          color: #111;
        }
      </style>
    </head>
    <body>
      <div class="wrap">
        <div class="loading">正在加载...</div>
        <div class="pics">
        </div>
      </div>
      <script>
      </script>
    </body>
    </html>

    Promise是空泛异步管理指标以致对其进展种种操作的零器件。 其实那样聊起来照旧相比抽象,那么我们差不离的知晓正是,管理异步操作通常是利用回调函数和事件。

    什么获取 Headless Chrome

    目前,Mac 上 Chrome 59 beta 版本与 Linux 上的 Chrome 57 已经上马援助 headless 脾气。Windows 上 Chrome 临时不帮忙,能够使用 Chrome Canary 60 举行开荒。

    经过回调实现异步

    单线程发生了多少个难点。当 JavaScript 实施三个“缓慢”的管理程序,比如浏览器中的 Ajax 央浼只怕服务器上的数据库操作时,会发出什么样?这一个操作可能要求几分钟 – 依然几分钟。浏览器在等待响适这时会被锁定。在服务器上,Node.js 应用将不可能管理任何的客户伏乞。

    减轻方案是异步管理。当结果就绪时,叁个进度被告知调用另三个函数,实际不是等待实现。这称为回调,它充当参数字传送递给其他异步函数。举例:

    doSomethingAsync(callback1卡塔尔国; console.log('finished'卡塔尔; // 当 doSomethingAsync 完结时调用 function callback1(error卡塔尔(英语:State of Qatar) { if (!error) console.log('doSomethingAsync complete'); }

    1
    2
    3
    4
    5
    6
    7
    doSomethingAsync(callback1);
    console.log('finished');
     
    // 当 doSomethingAsync 完成时调用
    function callback1(error) {
      if (!error) console.log('doSomethingAsync complete');
    }

    doSomethingAsync() 选拔回调函数作为参数(只传递该函数的援引,由此支付超级小卡塔尔(قطر‎。doSomethingAsync() 实施多短时间并不根本;我们所精通的是,callback1() 将在现在某些时刻施行。调控台将显得:

    finished doSomethingAsync complete

    1
    2
    finished
    doSomethingAsync complete

    【嵌牛导读】Promise 想必大家都不行纯熟,思考就那么多少个api,然而你确实驾驭 Promise 吗?

    单纯性要求

    最简单易行的,即是将异步叁个个来管理,转为二个相似同步的方法来拍卖。 先来大约的兑现一个单个 Image 来加载的 thenable 函数和二个管理函数重临结果的函数。

    JavaScript

    function loadImg (url) { return new Promise((resolve, reject) => { const img = new Image() img.onload = function () { resolve(img) } img.onerror = reject img.src = url }) }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function loadImg (url) {
      return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = function () {
          resolve(img)
        }
        img.onerror = reject
        img.src = url
      })
    }

    异步转同步的消除思想是:当第一个 loadImg(urls[1]卡塔尔(قطر‎ 完结后再调用 loadImg(urls[2]卡塔尔国,依次往下。借使 loadImg(卡塔尔是贰个联合具名函数,那么很自然的想到用__循环__。

    JavaScript

    for (let i = 0; i < urls.length; i ) { loadImg(urls[i]) }

    1
    2
    3
    for (let i = 0; i < urls.length; i ) {
      loadImg(urls[i])
    }

    当 loadImg(卡塔尔(قطر‎ 为异步时,大家就只能用 Promise chain 来完结,最后形成这种方法的调用:

    JavaScript

    loadImg(urls[0]) .then(addToHtml) .then(()=>loadImg(urls[1])) .then(addToHtml) //... .then(()=>loadImg(urls[3])) .then(addToHtml)

    1
    2
    3
    4
    5
    6
    7
    loadImg(urls[0])
      .then(addToHtml)
      .then(()=>loadImg(urls[1]))
      .then(addToHtml)
      //...
      .then(()=>loadImg(urls[3]))
      .then(addToHtml)

    那大家用四当中级变量来存款和储蓄当前的 promise ,犹如链表的游标一样,纠正后的 for 循环代码如下:

    JavaScript

    let promise = Promise.resolve() for (let i = 0; i < urls.length; i ) { promise = promise .then(()=>loadImg(urls[i])) .then(addToHtml) }

    1
    2
    3
    4
    5
    6
    let promise = Promise.resolve()
    for (let i = 0; i < urls.length; i ) {
    promise = promise
    .then(()=>loadImg(urls[i]))
    .then(addToHtml)
    }

    promise 变量仿佛三个迭代器,不断指向最新的回到的 Promise,那我们就更是利用 reduce 来简化代码。

    JavaScript

    urls.reduce((promise, url) => { return promise .then(()=>loadImg(url)) .then(addToHtml) }, Promise.resolve())

    1
    2
    3
    4
    5
    urls.reduce((promise, url) => {
      return promise
        .then(()=>loadImg(url))
        .then(addToHtml)
    }, Promise.resolve())

    在程序设计中,是能够经过函数的__递归__来落实循环语句的。所以大家将上边的代码改成__递归__:

    JavaScript

    function syncLoad (index) { if (index >= urls.length) return loadImg(urls[index]).then(img => { // process img addToHtml(img) syncLoad (index 1) }) } // 调用 syncLoad(0)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function syncLoad (index) {
      if (index >= urls.length) return
          loadImg(urls[index]).then(img => {
          // process img
          addToHtml(img)
          syncLoad (index 1)
        })
    }
     
    // 调用
    syncLoad(0)

    好了二个简便的异步转同步的贯彻情势就早就做到,大家来测量试验一下。 这么些达成的简要版本已经达成没难点,可是最上面包车型大巴正在加载还在,那大家怎么在函数外界知道那么些递归的了断,并遮盖掉那些DOM 呢?Promise.then(卡塔尔(英语:State of Qatar) 相似再次来到的是 thenable 函数 大家只需求在 syncLoad 内部传递那条 Promise 链,直到最终的函数再次回到。

    JavaScript

    function syncLoad (index) { if (index >= urls.length) return Promise.resolve() return loadImg(urls[index]) .then(img => { addToHtml(img) return syncLoad (index 1) }) } // 调用 syncLoad(0) .then(() => { document.querySelector('.loading').style.display = 'none' })

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function syncLoad (index) {
      if (index >= urls.length) return Promise.resolve()
      return loadImg(urls[index])
        .then(img => {
          addToHtml(img)
          return syncLoad (index 1)
        })
    }
     
    // 调用
    syncLoad(0)
      .then(() => {
      document.querySelector('.loading').style.display = 'none'
    })

    目前大家再来完备一下以此函数,让它越是通用,它承当__异步函数__、异步函数要求的参数数组、__异步函数的回调函数__四个参数。何况会记录调用失利的参数,在最后回到到函数外界。此外大家能够思谋一下怎么 catch 要在终极的 then 在此之前。

    JavaScript

    function syncLoad (fn, arr, handler) { if (typeof fn !== 'function')throw TypeError('第二个参数必需是function'卡塔尔 if (!Array.isArray(arr卡塔尔卡塔尔(قطر‎throw TypeError('第4个参数必需是数组'卡塔尔 handler = typeof fn === 'function' ? handler : function (卡塔尔国 {} const errors = [] return load(0) function load (index) { if (index >= arr.length) { return errors.length > 0 ? Promise.reject(errors) : Promise.resolve() } return fn(arr[index]) .then(data => { handler(data) }) .catch(err => { console.log(err) errors.push(arr[index]) return load(index 1) }) .then(() => { return load (index 1) }) } } // 调用 syncLoad(loadImg, urls, addToHtml) .then(() => { document.querySelector('.loading').style.display = 'none' }) .catch(console.log)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    function syncLoad (fn, arr, handler) {
      if (typeof fn !== 'function') throw TypeError('第一个参数必须是function')
      if (!Array.isArray(arr)) throw TypeError('第二个参数必须是数组')
      handler = typeof fn === 'function' ? handler : function () {}
      const errors = []
      return load(0)
      function load (index) {
        if (index >= arr.length) {
          return errors.length > 0 ? Promise.reject(errors) : Promise.resolve()
        }
        return fn(arr[index])
          .then(data => {
            handler(data)
          })
          .catch(err => {
            console.log(err)              
            errors.push(arr[index])
            return load(index 1)
          })
          .then(() => {
            return load (index 1)
          })
      }
    }
     
    // 调用
    syncLoad(loadImg, urls, addToHtml)
      .then(() => {
        document.querySelector('.loading').style.display = 'none'
      })
      .catch(console.log)

    demo1地址:纯净央求 – 八个 Promise 同步化

    至此,那么些函数如故有挺多不通用的标题,例如:管理函数必须意气风发律,无法是种种分裂的异步函数组成的连串,异步的回调函数也只可以是意气风发种等。关于这种情势的更详尽的描述能够看作者事前写的生龙活虎篇文章 Koa引用库之Koa-compose。

    理之当然这种异步转同步的措施在这里三个例子中实际不是最佳的解法,但当有切合的业务场景的时候,那是很普遍的解决方案。

    例如: let P = new Promise((resolve,reject)=>{

    何以在顶峰中央银行使

    在Mac上利用前,建议先绑定 Chrome 的外号

    JavaScript

    alias google-chrome="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

    1
    alias google-chrome="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

    Linux下没有需求绑定外号,从官网络下载最新版 Chrome 之后直接运营以下命令就能够。

    接下来,在极端中输入:

    google-chrome --headless --disable-gpu --remote-debugging-port=9222

    1
    google-chrome --headless --disable-gpu --remote-debugging-port=9222  https://github.com

    追加 –disable-gpu 首假设为着挡住现阶段说不佳接触的大错特错。

    当时,Headless Chrome已经成功运维了。打开浏览器,输入 http://localhost:9222,你会见到如下的界面:新葡亰496net 2

    在极限中,大家仍然是能够做以下操作:

    收获荧屏截图:

    JavaScript

    google-chrome --headless --disable-gpu --screenshot --window-size=1280,1696

    1
    google-chrome --headless --disable-gpu --screenshot --window-size=1280,1696 https://github.com

    得到页面为PDF:

    JavaScript

    google-chrome --headless --disable-gpu --print-to-pdf

    1
    google-chrome --headless --disable-gpu --print-to-pdf https://github.com

    打字与印刷页面DOM:

    JavaScript

    google-chrome --headless --disable-gpu --dump-dom

    1
    google-chrome --headless --disable-gpu --dump-dom https://github.com/

    回调地狱

    常备,回调只由一个异步函数调用。因而,能够使用轻巧、佚名的内联函数:

    doSomethingAsync(error => { if (!error) console.log('doSomethingAsync complete'); });

    1
    2
    3
    doSomethingAsync(error => {
      if (!error) console.log('doSomethingAsync complete');
    });

    一雨后春笋的多个或越多异步调用可以通过嵌套回调函数来一而再再而三造成。举例:

    async1((err, res) => { if (!err) async2(res, (err, res) => { if (!err) async3(res, (err, res) => { console.log('async1, async2, async3 complete.'); }); }); });

    1
    2
    3
    4
    5
    6
    7
    async1((err, res) => {
      if (!err) async2(res, (err, res) => {
        if (!err) async3(res, (err, res) => {
          console.log('async1, async2, async3 complete.');
        });
      });
    });

    不佳的是,这引进了回调地狱 —— 三个劣迹斑斑的定义,以致有特地的网页介绍!代码很难读,并且在加多错误管理逻辑时变得更糟。

    回调鬼世界在客商端编码中相对少见。假若你调用 Ajax 诉求、更新 DOM 并等待动漫完毕,可能须求嵌套两到三层,但是普通还算可治本。

    操作系统或服务器进度的意况就差异了。贰个 Node.js API 能够接过文件上传,更新四个数据库表,写入日志,并在发送响应在此之前行行下一步的 API 调用。

    【嵌牛鼻子】:Promise

    并发央求

    终究同大器晚成域名下能够并发五个 HTTP 央求,对于这种无需按顺序加载,只供给按梯次来管理的现身须求,Promise.all 是最佳的扑灭办法。因为Promise.all 是原生函数,大家就引述文书档案来解释一下。

    Promise.all(iterable卡塔尔(英语:State of Qatar) 方法指当全数在可迭代参数中的 promises 已做到,也许第多个传递的 promise(指 reject)失利时,再次来到 promise。
    出自 Promise.all() – JavaScript | MDN

    那大家就把demo1中的例子改一下:

    JavaScript

    const promises = urls.map(loadImg卡塔尔(英语:State of Qatar) Promise.all(promises卡塔尔(英语:State of Qatar) .then(imgs => { imgs.forEach(addToHtml卡塔尔国document.querySelector('.loading'卡塔尔(英语:State of Qatar).style.display = 'none' }卡塔尔(قطر‎ .catch(err => { console.error(err, 'Promise.all 当此中一个面世错误,就能够reject。'卡塔尔(英语:State of Qatar) }卡塔尔国

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const promises = urls.map(loadImg)
    Promise.all(promises)
      .then(imgs => {
        imgs.forEach(addToHtml)
        document.querySelector('.loading').style.display = 'none'
      })
      .catch(err => {
        console.error(err, 'Promise.all 当其中一个出现错误,就会reject。')
      })

    demo2地址:并发乞求 – Promise.all

    let num = Math.random()

    远程序调整制

    在上文中叙述的都应用终端命令运转 Headless Chrome,下文以拿到截图为例,尝试什么在程序里决定 Headless Chrome。

    设置依赖

    JavaScript

    npm install lighthouse chrome-remote-interface --save

    1
    npm install lighthouse chrome-remote-interface --save

    实现截图的大约思路为:通过动用 lighthouse 运营 Headless Chrome,然后经过 chrome-remote-interface 长间距调节浏览器,使用 Page 监察和控制页面包车型地铁加载,使用 Emulation 模块调治视口缩放,最后生成一张截图。

    JavaScript

    const { ChromeLauncher } = require('lighthouse/lighthouse-cli/chrome-launcher') const chrome = require('chrome-remote-interface') const fs = require('fs') const deviceMetrics = { width: 1200, height: 800, deviceScaleFactor: 0, mobile: false, fitWindow: false } const screenshotMetrics = { width: deviceMetrics.width, height: deviceMetrics.height } let protocol let launcher function launchChrome () { const launcher = new ChromeLauncher({ port: 9222, autoSelectChrome: true, additionalFlags: ['--window-size=412,732', '--disable-gpu', '--headless'] }卡塔尔(英语:State of Qatar) return launcher.run(卡塔尔.then((卡塔尔国 => launcher卡塔尔国 } function getScreenShot (卡塔尔(قطر‎ { const { Page, Emulation } = protocol return Page.enable(卡塔尔 .then((卡塔尔国 => { Emulation.setDeviceMetricsOverride(deviceMetrics卡塔尔 // 配置浏览器尺寸 Emulation.setVisibleSize(screenshotMetrics卡塔尔国 // 配置截图尺寸 Page.navigate({ url: '' }) return new Promise((resolve, reject) => { Page.loadEventFired(() => { resolve(Page.captureScreenshot({ format: 'jpeg', fromSurface: true })) }) }) }) .then(image => { const buffer = new Buffer(image.data, 'base64') return new Promise((resolve, reject) => { fs.writeFile('output.jpeg', buffer, 'base64', err => { if (err) return reject(err) resolve() }) }) }) } launchChrome() .then(Launcher => { launcher = Launcher return new Promise((resolve, reject) =>{ chrome(Protocol => { protocol = Protocol resolve() }).on('error', err => { reject(err) }) }) }) .then(getScreenShot) .then(() => { protocol.close() launcher.kill() }) .catch(console.error)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    const { ChromeLauncher } = require('lighthouse/lighthouse-cli/chrome-launcher')
    const chrome = require('chrome-remote-interface')
    const fs = require('fs')
    const deviceMetrics = {
      width: 1200,
      height: 800,
      deviceScaleFactor: 0,
      mobile: false,
      fitWindow: false
    }
    const screenshotMetrics = {
      width: deviceMetrics.width,
      height: deviceMetrics.height
    }
    let protocol
    let launcher
     
    function launchChrome () {
      const launcher = new ChromeLauncher({
        port: 9222,
        autoSelectChrome: true,
        additionalFlags: ['--window-size=412,732', '--disable-gpu', '--headless']
      })
      return launcher.run().then(() => launcher)
    }
    function getScreenShot () {
      const { Page, Emulation } = protocol
      return Page.enable()
        .then(() => {
          Emulation.setDeviceMetricsOverride(deviceMetrics) // 配置浏览器尺寸
          Emulation.setVisibleSize(screenshotMetrics) // 配置截图尺寸
          Page.navigate({ url: 'https://github.com/' })
          return new Promise((resolve, reject) => {
            Page.loadEventFired(() => {
              resolve(Page.captureScreenshot({ format: 'jpeg', fromSurface: true }))
            })
          })
        })
        .then(image => {
          const buffer = new Buffer(image.data, 'base64')
          return new Promise((resolve, reject) => {
            fs.writeFile('output.jpeg', buffer, 'base64', err => {
              if (err) return reject(err)
              resolve()
            })
          })
        })
    }
    launchChrome()
      .then(Launcher => {
        launcher = Launcher
        return new Promise((resolve, reject) =>{
          chrome(Protocol => {
            protocol = Protocol
            resolve()
          }).on('error', err => { reject(err) })
        })
      })
      .then(getScreenShot)
      .then(() => {
        protocol.close()
        launcher.kill()
      })
      .catch(console.error)

    此处运用 lighthouse 提供的 ChromeLauncher 模块来调用 Chrome,要是Computer上设置了Chrome Canary,lighthouse 私下认可会运维 Chrome Canary,能够将 autoSelectChrome 设置为false 然后活动选取采用什么版本。

    透过 chrome-remote-interface 合作 Headless Chrome,我们还足以做更加多事情。

    利用 CSS 和 DOM 模块,可以得到和装置页面中的 DOM 节点内容和 CSS 样式。

    JavaScript

    function getStyle () { const { Page, CSS, DOM } = protocol return Promise.all([ DOM.enable(), CSS.enable(), Page.enable() ]) .then(() => { Page.navigate({ url: '' }) return new Promise((resolve, _) => { Page.loadEventFired(() => { resolve(DOM.getDocument()) }) }) }) .then(res => res.root.nodeId) .then(nodeId => DOM.querySelector({ selector: '.btn-primary', nodeId })) .then(({ nodeId }) => CSS.getComputedStyleForNode({ nodeId })) .then(style => { console.log(style) }) }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function getStyle () {
      const { Page, CSS, DOM } = protocol
      return Promise.all([
          DOM.enable(),
          CSS.enable(),
          Page.enable()
        ])
        .then(() => {
          Page.navigate({ url: 'https://github.com/' })
          return new Promise((resolve, _) => {
            Page.loadEventFired(() => { resolve(DOM.getDocument()) })
          })
        })
        .then(res => res.root.nodeId)
        .then(nodeId => DOM.querySelector({ selector: '.btn-primary', nodeId }))
        .then(({ nodeId }) => CSS.getComputedStyleForNode({ nodeId }))
        .then(style => { console.log(style) })
    }

    动用 Runtime 模块,可以在页面运转时举行 JS 脚本。

    JavaScript

    function search () { const { Page, Runtime } = protocol return Promise.all([ Page.enable() ]) .then(() => { Page.navigate({ url: '' }) return new Promise((resolve, _) => { Page.loadEventFired(() => { resolve() }) }) }) .then(() => { const code = [ 'var input = document.querySelector('.s_ipt')', 'var btn = document.querySelector('#su')', 'input.value='123'' ].join(';') return Runtime.evaluate({ expression: code }) }) .then(() => { return new Promise((resolve, _) => { setTimeout(() => { resolve(Page.captureScreenshot({ format: 'jpeg', fromSurface: true })) }, 3000) }) }) .then(image => { const buffer = new Buffer(image.data, 'base64') return new Promise((resolve, reject) => { fs.writeFile('output.jpeg', buffer, 'base64', err => { if (err) return reject(err) resolve() }) }) }) }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    function search () {
      const { Page, Runtime } = protocol
      return Promise.all([
          Page.enable()
        ])
        .then(() => {
          Page.navigate({ url: 'https://www.baidu.com/' })
          return new Promise((resolve, _) => {
            Page.loadEventFired(() => { resolve() })
          })
        })
        .then(() => {
          const code = [
            'var input = document.querySelector('.s_ipt')',
            'var btn = document.querySelector('#su')',
            'input.value='123''
          ].join(';')
          return Runtime.evaluate({ expression: code })
        })
        .then(() => {
          return new Promise((resolve, _) => {
            setTimeout(() => {
              resolve(Page.captureScreenshot({ format: 'jpeg', fromSurface: true }))
            }, 3000)
          })
        })
        .then(image => {
          const buffer = new Buffer(image.data, 'base64')
          return new Promise((resolve, reject) => {
            fs.writeFile('output.jpeg', buffer, 'base64', err => {
              if (err) return reject(err)
              resolve()
            })
          })
        })
    }

    应用 Network 模块,能够读取并安装 UserAgent 和 Cookie 等音信。

    JavaScript

    function setUAandCookie () { const { Page, Network } = protocol return Promise.all([ Network.enable(), Page.enable() ]) .then(() => { const userAgent = Network.setUserAgentOverride({ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.71 Safari/537.36" }) Network.setCookie({ url: '', name: 'test', value: '123', domain: '.github.com', path: '/', httpOnly: true }) Page.navigate({ url: '' }) return new Promise((resolve, _) => { Page.loadEventFired(() => { resolve() }) }) }) .then(() => { return Network.getCookies() }) .then(console.log) }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function setUAandCookie () {
      const { Page, Network } = protocol
      return Promise.all([
          Network.enable(),
          Page.enable()
        ])
        .then(() => {
          const userAgent =
          Network.setUserAgentOverride({ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.71 Safari/537.36" })
          Network.setCookie({
            url: 'https://github.com',
            name: 'test',
            value: '123',
            domain: '.github.com',
            path: '/',
            httpOnly: true
          })
          Page.navigate({ url: 'https://github.com/' })
          return new Promise((resolve, _) => {
            Page.loadEventFired(() => { resolve() })
          })
        })
        .then(() => {
          return Network.getCookies()
        })
        .then(console.log)
    }

    Promises

    ES2015(ES6) 引入了 Promises。回调函数依然有用,可是Promises 提供了更清晰的链式异步命令语法,因而得以串联运维(下个章节会讲)。

    希图根据 Promise 封装,异步回调函数必需回到八个 Promise 对象。Promise 对象会试行以下多个函数(作为参数字传送递的)个中之风流浪漫:

    • resolve:推行成功回调
    • reject:实践倒闭回调

    以下例子,database API 提供了一个 connect() 方法,接纳一个回调函数。外界的 asyncDBconnect() 函数立时再次回到了叁个新的 Promise,后生可畏旦三番五次创立成功或破产,resolve()reject() 便会实践:

    const db = require('database'卡塔尔国; // 连接数据库 function asyncDBconnect(param卡塔尔 { return new Promise((resolve, reject卡塔尔(英语:State of Qatar) => { db.connect(param, (err, connection卡塔尔(قطر‎ => { if (err卡塔尔国 reject(err卡塔尔(قطر‎; else resolve(connection卡塔尔国; }卡塔尔(英语:State of Qatar); }卡塔尔(قطر‎; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const db = require('database');
     
    // 连接数据库
    function asyncDBconnect(param) {
     
      return new Promise((resolve, reject) => {
     
        db.connect(param, (err, connection) => {
          if (err) reject(err);
          else resolve(connection);
        });
     
      });
     
    }

    Node.js 8.0 以上提供了 util.promisify() 功能,能够把依照回调的函数转变来基于 Promise 的。有多个使用条件:

    1. 传播八个唯大器晚成的异步函数
    2. 盛传的函数希望是不对优先的(譬如:(err, value卡塔尔国 => …),error 参数在前,value 随后

    举例:

    // Node.js: 把 fs.readFile promise 化 const util = require('util'), fs = require('fs'), readFileAsync = util.promisify(fs.readFile); readFileAsync('file.txt');

    1
    2
    3
    4
    5
    6
    7
    // Node.js: 把 fs.readFile promise 化
    const
      util = require('util'),
      fs = require('fs'),
      readFileAsync = util.promisify(fs.readFile);
     
    readFileAsync('file.txt');

    种种库都会提供自身的 promisify 方法,寥寥几行也能够友善撸二个:

    // promisify 只接到三个函数参数 // 传入的函数选取 (err, data卡塔尔(قطر‎ 参数 function promisify(fn卡塔尔 { return function(卡塔尔(英语:State of Qatar) { return new Promise( (resolve, reject卡塔尔(قطر‎ => fn( ...Array.from(arguments卡塔尔, (err, data卡塔尔(英语:State of Qatar) => err ? reject(err卡塔尔(قطر‎ : resolve(data卡塔尔(英语:State of Qatar) 卡塔尔国 卡塔尔(قطر‎; } } // 比如 function wait(time, callback卡塔尔(英语:State of Qatar) { setTimeout((卡塔尔(英语:State of Qatar) => { callback(null, 'done'卡塔尔; }, time卡塔尔(英语:State of Qatar); } const asyncWait = promisify(wait卡塔尔(قطر‎; ayscWait(1000卡塔尔(قطر‎;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // promisify 只接收一个函数参数
    // 传入的函数接收 (err, data) 参数
    function promisify(fn) {
      return function() {
          return new Promise(
            (resolve, reject) => fn(
              ...Array.from(arguments),
            (err, data) => err ? reject(err) : resolve(data)
          )
        );
      }
    }
     
    // 举例
    function wait(time, callback) {
      setTimeout(() => { callback(null, 'done'); }, time);
    }
     
    const asyncWait = promisify(wait);
     
    ayscWait(1000);

    【嵌牛提问】:本文依据 Promise 的大器晚成部分知识点总括了十道题,看看你能做对几道。

    现身诉求,按梯次管理结果

    Promise.all 固然能并发八个乞求,然而假如中间某四个 promise 出错,整个 promise 会被 reject 。 webapp 里常用的财富预加载,或者加载的是 20 张逐帧图片,当互联网现身难题, 20 张图难免会有豆蔻梢头两张呼吁失利,借使战败后,直接甩掉别的被 resolve 的回到结果,就像有一些不妥,大家就算通晓怎么样图片出错了,把失误的图样再做叁遍呼吁或着用占位图补上就好。 上节中的代码 const promises = urls.map(loadImg卡塔尔国运转后,全体都图片央浼都已发出去了,大家只要按梯次依次管理 promises 这几个数组中的 Promise 实例就好了,先用一个简短点的 for 循环来落到实处以下,跟第2节中的单生龙活虎央浼同样,利用 Promise 链来挨门逐户管理。

    JavaScript

    let task = Promise.resolve() for (let i = 0; i < promises.length; i ) { task = task.then(() => promises[i]).then(addToHtml) }

    1
    2
    3
    4
    let task = Promise.resolve()
    for (let i = 0; i < promises.length; i ) {
      task = task.then(() => promises[i]).then(addToHtml)
    }

    改成 reduce 版本

    JavaScript

    promises.reduce((task, imgPromise) => { return task.then(() => imgPromise).then(addToHtml) }, Promise.resolve())

    1
    2
    3
    promises.reduce((task, imgPromise) => {
      return task.then(() => imgPromise).then(addToHtml)
    }, Promise.resolve())

    demo3地址:Promise 并发央求,顺序管理结果

    setTimeout(()=>{

    在 Karma 中应用 Headless Chrome 举办单元测量试验

    对待于 PhantomJS 等,使用 Headless Chrome 做单元测量检验越发贴近浏览器开荒境遇。同有的时候候 PhantomJS 作者也早已功成身退,在 Chrome 揭橥 Headless 方式后,公布通知不再维护 PhantomJS 项目。

    安装信赖

    JavaScript

    npm install jasmine-core karma karma-chrome-launcher karma-jasmine -D

    1
    npm install jasmine-core karma karma-chrome-launcher karma-jasmine -D

    配置 Karma

    JavaScript

    // karma.conf.js module.exports = function (config) { config.set({ frameworks: ['jasmine'], files: ['./test.js'], browsers: ["Chrome_Beta_Headless"], customLaunchers: { Chrome_Beta_Headless: { base: 'Chrome', flags: [ '--headless', '--disable-gpu', '--remote-debugging-port=9222' ] } }, browserConsoleLogOptions: { level: 'log', terminal: true }, reporters: ['progress'], autoWatch: false, singleRun: true }) }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // karma.conf.js
    module.exports = function (config) {
      config.set({
        frameworks: ['jasmine'],
        files: ['./test.js'],
        browsers: ["Chrome_Beta_Headless"],
        customLaunchers: {
          Chrome_Beta_Headless: {
            base: 'Chrome',
            flags: [
              '--headless',
              '--disable-gpu',
              '--remote-debugging-port=9222'
            ]
          }
        },
        browserConsoleLogOptions: {
          level: 'log',
          terminal: true
        },
        reporters: ['progress'],
        autoWatch: false,
        singleRun: true
      })
    }

    编辑测验用例

    JavaScript

    // test.js describe('test', function() { it('should be true', function() { console.log(window.navigator.userAgent) expect(true).toEqual(true); }); });

    1
    2
    3
    4
    5
    6
    7
    // test.js
    describe('test', function() {
      it('should be true', function() {
        console.log(window.navigator.userAgent)
        expect(true).toEqual(true);
      });
    });

    配置npm script

    JavaScript

    // package.json ... scripts: { test: "karma start" } ...

    1
    2
    3
    4
    5
    6
    // package.json
    ...
    scripts: {
      test: "karma start"
    }
    ...

    在尖峰中运作

    JavaScript

    npm test

    1
    npm test

    结果新葡亰496net 3

    从重回结果中能够看见,测验已运营在 Headless Chrome 情状下。

    异步链式调用

    其余重返 Promise 的函数都能够因此 .then() 链式调用。前二个 resolve 的结果会传递给后二个:

    asyncDBconnect(''卡塔尔(英语:State of Qatar) .then(asyncGetSession卡塔尔 // 传递 asyncDBconnect 的结果 .then(asyncGetUser卡塔尔(英语:State of Qatar) // 传递 asyncGetSession 的结果 .then(asyncLogAccess卡塔尔(英语:State of Qatar) // 传递 asyncGetUser 的结果 .then(result => { // 同步函数 console.log('complete'卡塔尔国; // (传递 asyncLogAccess 的结果卡塔尔国return result; // (结果传给下叁个 .then(卡塔尔国卡塔尔(قطر‎ }卡塔尔 .catch(err => { // 任何叁个 reject 触发 console.log('error', err卡塔尔; }卡塔尔;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    asyncDBconnect('http://localhost:1234')
      .then(asyncGetSession)      // 传递 asyncDBconnect 的结果
      .then(asyncGetUser)         // 传递 asyncGetSession 的结果
      .then(asyncLogAccess)       // 传递 asyncGetUser 的结果
      .then(result => {           // 同步函数
        console.log('complete');  //   (传递 asyncLogAccess 的结果)
        return result;            //   (结果传给下一个 .then())
      })
      .catch(err => {             // 任何一个 reject 触发
        console.log('error', err);
      });

    一起函数也足以实施 .then(),再次回到的值传递给下一个 .then()(如果有)。

    当其余三个前边的 reject 触发时,.catch() 函数会被调用。触发 reject 的函数后边的 .then() 也不再试行。贯穿整个链条能够存在七个 .catch() 方法,进而捕获分化的失实。

    ES2018 引入了 .finally() 方法,它不管再次来到结果什么,都会实践最终逻辑 – 比方,清理操作,关闭数据库连接等等。当前独有 Chrome 和 Firefox 协助,可是 TC39 技委已经昭示了 .finally() 补丁。

    function doSomething(卡塔尔(قطر‎ { doSomething1(卡塔尔国 .then(doSomething2卡塔尔(قطر‎.then(doSomething3卡塔尔 .catch(err => { console.log(err卡塔尔国; }卡塔尔(英语:State of Qatar) .finally((卡塔尔(英语:State of Qatar)=> { // 清理操作放那儿! }卡塔尔国; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function doSomething() {
      doSomething1()
      .then(doSomething2)
      .then(doSomething3)
      .catch(err => {
        console.log(err);
      })
      .finally(() => {
        // 清理操作放这儿!
      });
    }

    【嵌牛正文】:以下 promise 均代表 Promise 实例,情状是 Node.js。

    操纵最大并发数

    这段日子我们来试着姣好一下地点的笔试题,这些实际上都__不供给调整最大并发数__。 20张图,分若干次加载,那用多少个 Promise.all 不就缓和了?然而用 Promise.all不可能侦听到每一张图片加载成功的风波。而用上生机勃勃节的办法,大家既可以并发央浼,又能按顺序响应图片加载成功的事件。

    JavaScript

    let index = 0 const step1 = [], step2 = [] while(index < 10) { step1.push(loadImg(`./images/pic/${index}.jpg`)) index = 1 } step1.reduce((task, imgPromise, i) => { return task .then(() => imgPromise) .then(() => { console.log(`第 ${i 1} 张图片加载实现.`卡塔尔(英语:State of Qatar) }卡塔尔 }, Promise.resolve(卡塔尔(قطر‎卡塔尔(قطر‎ .then((卡塔尔 => { console.log('>> 后边10张已经加载完!'卡塔尔(قطر‎ }卡塔尔(英语:State of Qatar) .then((卡塔尔国 => { while(index < 20卡塔尔 { step2.push(loadImg(`./images/pic/${index}.jpg`)) index = 1 } return step2.reduce((task, imgPromise, i) => { return task .then(() => imgPromise) .then(() => { console.log(`第 ${i 11} 张图片加载实现.`卡塔尔 }卡塔尔国 }, Promise.resolve(卡塔尔(英语:State of Qatar)卡塔尔国 }卡塔尔(英语:State of Qatar) .then((卡塔尔(英语:State of Qatar) => { console.log('>> 后边10张已经加载完'卡塔尔(قطر‎ }卡塔尔(قطر‎

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    let index = 0
    const step1 = [], step2 = []
     
    while(index < 10) {
      step1.push(loadImg(`./images/pic/${index}.jpg`))
      index = 1
    }
     
    step1.reduce((task, imgPromise, i) => {
      return task
        .then(() => imgPromise)
        .then(() => {
          console.log(`第 ${i 1} 张图片加载完成.`)
        })
    }, Promise.resolve())
      .then(() => {
        console.log('>> 前面10张已经加载完!')
      })
      .then(() => {
        while(index < 20) {
          step2.push(loadImg(`./images/pic/${index}.jpg`))
          index = 1
        }
        return step2.reduce((task, imgPromise, i) => {
          return task
            .then(() => imgPromise)
            .then(() => {
              console.log(`第 ${i 11} 张图片加载完成.`)
            })
        }, Promise.resolve())
      })
      .then(() => {
        console.log('>> 后面10张已经加载完')
      })

    地方的代码是瞄准难点的 hardcode ,倘诺笔试的时候能写出那些,都曾经是非常不利了,不过并未一位写出来,said…

    demo4地址(看调控台和网络央浼卡塔尔(英语:State of Qatar):Promise 分步加载 – 1

    那就是说大家在空虚一下代码,写一个通用的艺术出来,那个函数重回叁个Promise,还足以继续管理整个都图片加载完后的异步回调。

    JavaScript

    function stepLoad (urls, handler, stepNum) { const createPromises = function (now, stepNum) { let last = Math.min(stepNum now, urls.length) return urls.slice(now, last).map(handler) } let step = Promise.resolve() for (let i = 0; i < urls.length; i = stepNum) { step = step .then(() => { let promises = createPromises(i, stepNum) return promises.reduce((task, imgPromise, index) => { return task .then(() => imgPromise) .then(() => { console.log(`第 ${index 1

    • i} 张图片加载落成.`) }) }, Promise.resolve()) }) .then(() => { let current = Math.min(i stepNum, urls.length) console.log(`>> 总共${current}张已经加载完!`) }) } return step }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function stepLoad (urls, handler, stepNum) {
    const createPromises = function (now, stepNum) {
        let last = Math.min(stepNum now, urls.length)
        return urls.slice(now, last).map(handler)
      }
      let step = Promise.resolve()
      for (let i = 0; i < urls.length; i = stepNum) {
        step = step
          .then(() => {
            let promises = createPromises(i, stepNum)
            return promises.reduce((task, imgPromise, index) => {
              return task
                .then(() => imgPromise)
                .then(() => {
                  console.log(`第 ${index 1 i} 张图片加载完成.`)
                })
            }, Promise.resolve())
          })
          .then(() => {
            let current = Math.min(i stepNum, urls.length)
            console.log(`>> 总共${current}张已经加载完!`)
          })
      }
    return step
    }

    地方代码里的 for 也得以改成 reduce ,不过须要先将急需加载的 urls 按分步的多少,划分成数组,感兴趣的相恋的人能够团结写写看。

    demo5地址(看调节台和互联网要求卡塔尔(قطر‎:Promise 分步 – 2

    但上边的完成和大家说的__最大并发数调节__无妨关系啊,最大并发数调整是指:当加载 20 张图片加载的时候,先并发央浼 10 张图纸,当一张图纸加载成功后,又会继续倡导一张图纸的乞请,让并发数保持在 十个,直到须求加载的图片都全体发起号令。那些在写爬虫中得以说是比较广泛的使用处境了。 那么大家总局方的有个别文化,大家用三种艺术来贯彻那几个成效。

    if(num>.5){

    小结

    本文简介了刹那间 Headless Chrome 在极限的用法,以至哪些使用 Headless Chrome 获取截图、获取页面中的CSS和DOM、设置UA和Cookie、运转JS脚本、配合Karma 举办单元测验。接下来,就等着你探求越多关于 Headless Chrome 的用法了…

    参考:

    https://developers.google.com/web/updates/2017/04/headless-chrome
    How to install and use Headless Chrome on OSX

    1 赞 1 收藏 评论

    新葡亰496net 4

    应用 Promise.all(卡塔尔(英语:State of Qatar) 管理多个异步操作

    Promise .then() 方法用于各样推行的异步函数。假如不关怀顺序 – 举例,伊始化不相干的组件 – 全体异步函数同期开动,直到最慢的函数实行 resolve,整个流程甘休。

    Promise.all() 适用于这种景观,它接收二个函数数组况兼重回另三个Promise。举个例子:

    Promise.all([ async1, async2, async3 ]卡塔尔(قطر‎ .then(values => { // 重返值的数组 console.log(values卡塔尔国; // (与函数数组顺序风华正茂致卡塔尔 return values; }卡塔尔国 .catch(err => { // 任风姿浪漫 reject 被触发 console.log('error', err卡塔尔(英语:State of Qatar); }卡塔尔(قطر‎;

    1
    2
    3
    4
    5
    6
    7
    8
    Promise.all([ async1, async2, async3 ])
      .then(values => {           // 返回值的数组
        console.log(values);      // (与函数数组顺序一致)
        return values;
      })
      .catch(err => {             // 任一 reject 被触发
        console.log('error', err);
      });

    轻巧二个异步函数 rejectPromise.all() 会立时甘休。

    题目一

    运用递归

    举例我们的最大并发数是 4 ,这种措施的首要性观念是一定于 4 个__纯净央求__的 Promise 异步职分在相同的时间运维运维,4 个十足须求不断递归取图片 URAV4L 数组中的 UPAJEROL 发起倡议,直到 UTiguanL 全部取完,最后再利用 Promise.all 来管理最终还在呼吁中的异步职务,大家复用首节__递归__本子的笔触来兑现那个效应:

    JavaScript

    function limitLoad (urls, handler, limit) { const sequence = [].concat(urls卡塔尔(英语:State of Qatar) // 对数组做一个拷贝 let count = 0 const promises = [] const load = function () { if (sequence.length <= 0 || count > limit) return count = 1 console.log(`脚下并发数: ${count}`) return handler(sequence.shift()) .catch(err => { console.error(err) }) .then(() => { count -= 1 console.log(`一时并发数:${count}`) }) .then(() => load()) } for(let i = 0; i < limit && i < sequence.length; i ){ promises.push(load()) } return Promise.all(promises) }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function limitLoad (urls, handler, limit) {
      const sequence = [].concat(urls) // 对数组做一个拷贝
      let count = 0
      const promises = []
     
      const load = function () {
        if (sequence.length <= 0 || count > limit) return
        count = 1
        console.log(`当前并发数: ${count}`)
        return handler(sequence.shift())
          .catch(err => {
            console.error(err)
          })
          .then(() => {
            count -= 1
            console.log(`当前并发数:${count}`)
          })
          .then(() => load())
      }
     
      for(let i = 0; i < limit && i < sequence.length; i ){
        promises.push(load())
      }
      return Promise.all(promises)
    }

    设定最大伏乞数为 5,Chrome 中号召加载的 timeline :新葡亰496net 5

    demo6地址(看调控台和网络恳求卡塔尔(英语:State of Qatar):Promise 调整最大并发数 – 方法1

    resolve('成功')

    使用 Promise.race(卡塔尔(قطر‎ 处理多个异步操作

    Promise.race()Promise.all() 极度相符,不一样之处在于,当第1个Promise resolve 恐怕 reject 时,它将会 resolve 大概reject。只有最快的异步函数会被实施:

    Promise.race([ async1, async2, async3 ]) .then(value => { // 单一值 console.log(value); return value; }) .catch(err => { // 任一 reject 被触发 console.log('error', err); });

    1
    2
    3
    4
    5
    6
    7
    8
    Promise.race([ async1, async2, async3 ])
      .then(value => {            // 单一值
        console.log(value);
        return value;
      })
      .catch(err => {             // 任一 reject 被触发
        console.log('error', err);
      });

    const promise = new Promise((resolve, reject) => {

    使用 Promise.race

    Promise.race 选用二个 Promise 数组,重临那几个数组中最早被 resolve 的 Promise 的重返值。终于找到 Promise.race 的施用景况了,先来使用这些措施落成的功能代码:

    JavaScript

    function limitLoad (urls, handler, limit) { const sequence = [].concat(urls卡塔尔国 // 对数组做多个拷贝 let count = 0 let promises const wrapHandler = function (url) { const promise = handler(url卡塔尔国.then(img => { return { img, index: promise } }卡塔尔 return promise } //并发诉求到最大数 promises = sequence.splice(0, limit卡塔尔国.map(url => { return wrapHandler(url卡塔尔(قطر‎ }卡塔尔 // limit 大于一切图片数, 并发全部伸手 if (sequence.length <= 0卡塔尔(قطر‎ { return Promise.all(promises卡塔尔 } return sequence.reduce((last, url卡塔尔国 => { return last.then((卡塔尔国 => { return Promise.race(promises卡塔尔国 }卡塔尔(英语:State of Qatar).catch(err => { console.error(err卡塔尔}卡塔尔(英语:State of Qatar).then((res卡塔尔 => { let pos = promises.findIndex(item => { return item == res.index }卡塔尔(英语:State of Qatar) promises.splice(pos, 1卡塔尔国promises.push(wrapHandler(url卡塔尔(英语:State of Qatar)卡塔尔 }卡塔尔(قطر‎ }, Promise.resolve(卡塔尔(قطر‎卡塔尔国.then((卡塔尔国 => { return Promise.all(promises卡塔尔(英语:State of Qatar) }卡塔尔国 }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    function limitLoad (urls, handler, limit) {
      const sequence = [].concat(urls) // 对数组做一个拷贝
      let count = 0
      let promises
      const wrapHandler = function (url) {
        const promise = handler(url).then(img => {
          return { img, index: promise }
        })
        return promise
      }
      //并发请求到最大数
      promises = sequence.splice(0, limit).map(url => {
        return wrapHandler(url)
      })
      // limit 大于全部图片数, 并发全部请求
      if (sequence.length <= 0) {
        return Promise.all(promises)
      }
      return sequence.reduce((last, url) => {
        return last.then(() => {
          return Promise.race(promises)
        }).catch(err => {
          console.error(err)
        }).then((res) => {
          let pos = promises.findIndex(item => {
            return item == res.index
          })
          promises.splice(pos, 1)
          promises.push(wrapHandler(url))
        })
      }, Promise.resolve()).then(() => {
        return Promise.all(promises)
      })
    }

    设定最大乞求数为 5,Chrome 中呼吁加载的 timeline :新葡亰496net 6

    demo7地址(看调控台和网络须求卡塔尔国:Promise 调节最大并发数 – 方法2

    在行使 Promise.race 完结这一个意义,首假设绵绵的调用 Promise.race 来回到已经被 resolve 的天职,然后从 promises 中删掉那么些 Promise 对象,再参与一个新的 Promise,直到整个的 U福特ExplorerL 被取完,最终再使用 Promise.all 来管理全数图片达成后的回调。

    }else{

    前途光明呢?

    Promise 减弱了回调鬼世界,然则引进了别的的题目。

    学科平常不提,整个 Promise 链条是异步的,风流倜傥多元的 Promise 函数都得回到本身的 Promise 或许在最后的 .then().catch() 或者 .finally() 方法里面实行回调。

    自家也认同:Promise 烦懑了笔者比较久。语法看起来比回调要复杂,好多地方会出错,调节和测验也成难点。然则,学习根底依旧很主要滴。

    延伸阅读:

    • MDN Promise documentation
    • JavaScript Promises: an Introduction
    • JavaScript Promises … In Wicked Detail
    • Promises for asynchronous programming

      console.log(1)

    写在结尾

    因为做事其间大批量使用 ES6 的语法,Koa 中的 await/async 又是 Promise 的语法糖,所以了然 Promise 各样流程序调整制是对本身的话是特别主要的。写的有不了然的地点和有错误的地点接待我们留言指正,其它还应该有任何未有涉及到的情势也请大家提供一下新的方法和方法。

    reject('失败')

    新葡亰496net,Async/Await

    Promise 看起来有一点点复杂,所以 ES2017 引进了 asyncawait。即使只是语法糖,却使 Promise 特别方便,并且能够免止 .then() 链式调用的难题。看下边选取 Promise 的事例:

    function connect() { return new Promise((resolve, reject) => { asyncDBconnect(''卡塔尔国 .then(asyncGetSession).then(asyncGetUser卡塔尔国 .then(asyncLogAccess卡塔尔(قطر‎ .then(result => resolve(result卡塔尔国卡塔尔国 .catch(err => reject(err卡塔尔卡塔尔(英语:State of Qatar) }卡塔尔国; } // 运转 connect 方法 (自推长势势卡塔尔(英语:State of Qatar) ((卡塔尔国 => { connect(卡塔尔(英语:State of Qatar); .then(result => console.log(result卡塔尔(قطر‎卡塔尔 .catch(err => console.log(err卡塔尔卡塔尔(قطر‎ }卡塔尔(قطر‎(卡塔尔(英语:State of Qatar);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function connect() {
     
      return new Promise((resolve, reject) => {
     
        asyncDBconnect('http://localhost:1234')
          .then(asyncGetSession)
          .then(asyncGetUser)
          .then(asyncLogAccess)
          .then(result => resolve(result))
          .catch(err => reject(err))
     
      });
    }
     
    // 运行 connect 方法 (自执行方法)
    (() => {
      connect();
        .then(result => console.log(result))
        .catch(err => console.log(err))
    })();

    使用 async / await 重写上边包车型大巴代码:

    1. 表面方法用 async 声明
    2. 依据 Promise 的异步方法用 await 表明,能够保障下八个发令施行前,它已实行到位

    async function connect() { try { const connection = await asyncDBconnect(''卡塔尔(英语:State of Qatar), session = await asyncGetSession(connection卡塔尔(英语:State of Qatar), user = await asyncGetUser(session卡塔尔(英语:State of Qatar), log = await asyncLogAccess(user卡塔尔(قطر‎; return log; } catch (e卡塔尔(英语:State of Qatar) { console.log('error', err卡塔尔; return null; } } // 运转 connect 方法 (自实行异步函数卡塔尔 (async (卡塔尔(قطر‎ => { await connect(卡塔尔(英语:State of Qatar); })(卡塔尔(英语:State of Qatar);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    async function connect() {
     
      try {
        const
          connection = await asyncDBconnect('http://localhost:1234'),
          session = await asyncGetSession(connection),
          user = await asyncGetUser(session),
          log = await asyncLogAccess(user);
     
        return log;
      }
      catch (e) {
        console.log('error', err);
        return null;
      }
     
    }
     
    // 运行 connect 方法 (自执行异步函数)
    (async () => { await connect(); })();

    await 使各种异步调用看起来疑似同步的,同有的时候间不延误 JavaScript 的单线程管理。此外,async 函数总是回到一个 Promise 对象,因而它能够被其它 async 函数调用。

    async / await 恐怕不会让代码减少,不过有超多亮点:

    1. 语法更显然。括号更加少,出错的或许也愈来愈小。
    2. 调弄收拾更易于。能够在任何 await 证明处设置断点。
    3. 错误管理尚佳。try / catch 能够与联合代码应用相似的管理方式。
    4. 援救美好。全部浏览器(除了 IE 和 Opera Mini 卡塔尔(英语:State of Qatar)和 Node7.6 均已兑现。

    如是说,未有完备的…

      resolve()

    题外话

    咱们近年来有 1 个前端的 HC,base 卡萨布兰卡,一家全体 50 架飞机的物流公司的AI部门,必要专门的学业涉世五年以上,那是集团社招须要的。 感兴趣的就联系本身吗,Email: d2hlYX路虎极光vQGZveG1haWwuY29t

    }

    Promises, Promises

    async / await 照旧依附 Promise 对象,最终凭仗回调。你需求领会Promise 的专门的学问原理,它也并不生机勃勃致 Promise.all()Promise.race()。比较轻易忽略的是 Promise.all(),那一个命令比接受风度翩翩连串非亲非故的 await 命令更迅捷。

      console.log(2)

    参照他事他说加以考察资料

    • JavaScript Promise:简介 | Web | Google Developers
    • JavaScript Promise迷你书(中文版)

      1 赞 3 收藏 评论

    新葡亰496net 7

    },2000)

    一齐循环中的异步等待

    好几情形下,你想要在风华正茂道循环中调用异步函数。比方:

    async function process(array) { for (let i of array) { await doSomething(i); } }

    1
    2
    3
    4
    5
    async function process(array) {
      for (let i of array) {
        await doSomething(i);
      }
    }

    不起功效,下边包车型地铁代码也同等:

    async function process(array) { array.forEach(async i => { await doSomething(i); }); }

    1
    2
    3
    4
    5
    async function process(array) {
      array.forEach(async i => {
        await doSomething(i);
      });
    }

    循环本身保持同步,何况三番四遍在中间异步操作早先产生。

    ES2018 引入异步迭代器,除了 next() 方法重返七个 Promise 对象之外,与常规迭代器相近。由此,await 关键字能够与 for ... of 循环一齐利用,以串市价势运维异步操作。比如:

    async function process(array) { for await (let i of array) { doSomething(i); } }

    1
    2
    3
    4
    5
    async function process(array) {
      for await (let i of array) {
        doSomething(i);
      }
    }

    可是,在异步迭代器达成此前,最佳的方案是将数组每项 mapasync 函数,并用 Promise.all() 实施它们。比方:

    const todo = ['a', 'b', 'c'], alltodo = todo.map(async (v, i) => { console.log('iteration', i); await processSomething(v); }); await Promise.all(alltodo);

    1
    2
    3
    4
    5
    6
    7
    8
    const
      todo = ['a', 'b', 'c'],
      alltodo = todo.map(async (v, i) => {
        console.log('iteration', i);
        await processSomething(v);
    });
     
    await Promise.all(alltodo);

    如此有帮助推行并行职分,可是力所不及将叁回迭代结果传递给另三遍迭代,並且映射大数组只怕会损耗总结品质。

    })

    })P.then((value)=>{console.log(value)

    丑陋的 try/catch

    如果施行停业的 await 未有包装 try / catchasync 函数将静默退出。假若有一长串异步 await 命令,必要多少个 try / catch 包裹。

    代表方案是利用高阶函数来捕捉错误,不再要求 try / catch 了(感谢@wesbos的建议):

    async function connect() { const connection = await asyncDBconnect(''卡塔尔国, session = await asyncGetSession(connection卡塔尔(قطر‎, user = await asyncGetUser(session卡塔尔(قطر‎, log = await asyncLogAccess(user卡塔尔(英语:State of Qatar); return true; } // 使用高阶函数捕获错误 function catchErrors(fn卡塔尔(قطر‎ { return function (...args卡塔尔 { return fn(...args卡塔尔国.catch(err => { console.log('E福睿斯RO昂Cora', err卡塔尔; }卡塔尔; } } (async (卡塔尔(قطر‎ => { await catchErrors(connect卡塔尔(英语:State of Qatar)(卡塔尔(قطر‎; }卡塔尔国(卡塔尔(قطر‎;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    async function connect() {
     
      const
        connection = await asyncDBconnect('http://localhost:1234'),
        session = await asyncGetSession(connection),
        user = await asyncGetUser(session),
        log = await asyncLogAccess(user);
     
      return true;
    }
     
    // 使用高阶函数捕获错误
    function catchErrors(fn) {
      return function (...args) {
        return fn(...args).catch(err => {
          console.log('ERROR', err);
        });
      }
    }
     
    (async () => {
      await catchErrors(connect)();
    })();

    当使用必需重回不一样于其余的谬误时,这种作法就不太实用了。

    固然有点劣点,async/await 依然 JavaScript 特别常有效的补给。越多资源:

    • MDN async 和 await
    • 异步函数 – 升高 Promise 的易用性
    • TC39 异步函数标准
    • 用异步函数简化异步编码

    promise.then(() => {

    },(reason)=>{

    JavaScript 之旅

    异步编程是 JavaScript 无法制止的挑战。回调在大许多用到中是至关重要的,可是轻便陷入深度嵌套的函数中。

    Promise 抽象了回调,但是有过多句法陷阱。调换原来就有函数只怕是生机勃勃件苦差事,·then() 链式调用看起来很混乱。

    很幸运,async/await 表明清晰。代码看起来是一路的,不过又不独自据有单个管理线程。它将改成您书写 JavaScript 的方式,以致令你更讲究 Promise – 假使没接触过的话。

    1 赞 收藏 评论

    新葡亰496net 8

      console.log(3)

    console.log(reason)

    })

    })

    console.log(4)

    二· 为啥使用Promise

    运行结果:

    动用pomise其实便是缓慢解决异步回调的嵌套的主题素材。上边不要紧大家来看一个例子: 

    1

    var ajax=function (){

    2

    $.ajax(url1,data1,function(res1){

    4

    $.ajax(url2,data2,function(res2){

    3

    $.ajax(url3,data3,function(res3){

    解说:Promise 结构函数是一块实行的,promise.then 中的函数是异步试行的。

    })

    题目二

    })

    const promise1 = new Promise((resolve, reject) => {

    })

      setTimeout(() => {

    }

        resolve('success')

    这种操作也有用过吗,也可以有人生机勃勃看此人写的真垃圾,确实作者自己水平有限。

      }, 1000)

    这种嵌套能够说是十分不团结,那么用pomise就很有次序性了。

    })

    let ajax=new Promise(function(resolve,reject){

    const promise2 = promise1.then(() => {

    $.ajax(url1,data1,function(res1){

      throw new Error('error!!!')

    resolve(res1)

    })

    },function)

    console.log('promise1', promise1)

    })

    console.log('promise2', promise2)

    ajax.then(function(data){

    setTimeout(() => {

    ajax1=new Promise(function(resolve,reject){

      console.log('promise1', promise1)

    $.ajax(url1,data,function(res1){

      console.log('promise2', promise2)

    resolve(res1)

    }, 2000)

    },function)

    运维结果:

    })

    promise1 Promise { <pending> }

    })

    promise2 Promise { <pending> }

    ajax1.then(function(data){

    (node:50928) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: error!!!

    .......

    (node:50928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

    })

    promise1 Promise { 'success' }

    ....依次类推

    promise2 Promise {

    三 Promise的实现

      <rejected> Error: error!!!

    const PENDING =  'pending';//初始态

        at promise.then (...)

    const FULFILLED = 'fulfilled';//初始态

        at <anonymous> }

    const REJECTED = 'rejected';//初始态

    表明:promise 有 3 种状态:pending、fulfilled 或 rejected。状态改动只好是 pending->fulfilled 只怕pending->rejected,状态风流倜傥旦更换则不可能再变。下面 promise2 并非promise1,而是重回的二个新的 Promise 实例。

    function Promise(executor){

    题目三

    let self = this;//先缓存当前promise实例

    const promise = new Promise((resolve, reject) => {

    self.status = PENDING;//设置情状

      resolve('success1')

    //定义寄存成功的回调的数组

      reject('error')

    self.onResolvedCallbacks = [];

      resolve('success2')

    //定义寄存退步回调的数组

    })

    self.onRejectedCallbacks = [];

    promise

    //当调用此办法的时候,如若promise状态为pending,的话能够转成成功态,如若已是成功态可能战败态了,则什么都不做

      .then((res) => {

    //2.1

        console.log('then: ', res)

    function resolve(value){ //2.1.1

      })

    if(value!=null &&value.then&&typeof value.then == 'function'){

      .catch((err) => {

    return value.then(resolve,reject);

        console.log('catch: ', err)

    }

      })

    //假诺是开始态,则转成成功态

    运行结果:

    setTimeout(function(){

    then: success1

    if(self.status == PENDING){

    演说:布局函数中的 resolve 或 reject 独有首先次实践有效,数次调用未有别的效果,呼应代码二结论:promise 状态风流罗曼蒂克旦退换则不可能再变。

    self.status = FULFILLED;

    题目四

    self.value = value;//成功后会得到二个值,那几个值不可能改

    Promise.resolve(1)

    //调用全体成功的回调

      .then((res) => {

    self.onResolvedCallbacks.forEach(cb=>cb(self.value));

        console.log(res)

    }

        return 2

    })

      })

    }

      .catch((err) => {

    function reject(reason){ //2.1.2

        return 3

    setTimeout(function(){

      })

    //就算是带头态,则转成失利态

      .then((res) => {

    if(self.status == PENDING){

        console.log(res)

    self.status = REJECTED;

      })

    self.value = reason;//退步的来头给了value

    运作结果:

    self.onRejectedCallbacks.forEach(cb=>cb(self.value));

    1

    }

    2

    });

    表明:promise 可以链式调用。聊起链式调用大家普通会想到通过 return this 实现,然则 Promise 实际不是这么完毕的。promise 每一回调用 .then 可能 .catch 都会回到一个新的 promise,进而达成了链式调用。

    }

    题目五

    try{

    const promise = new Promise((resolve, reject) => {

    //因为此函数实施也许会非常,所以要求捕获,假若出错了,须要用错误 对象reject

      setTimeout(() => {

    executor(resolve,reject);

        console.log('once')

    }catch(e){

        resolve('success')

    //若是那函数实践破产了,则用退步的来由reject那些promise

      }, 1000)

    reject(e);

    })

    };

    const start = Date.now()

    }

    promise.then((res) => {

    function resolvePromise(promise2,x,resolve,reject){

      console.log(res, Date.now() - start)

    if(promise2 === x){

    })

    return reject(new TypeError('循环援用'卡塔尔国卡塔尔(英语:State of Qatar);

    promise.then((res) => {

    }

      console.log(res, Date.now() - start)

    let called = false;//promise2是或不是业已resolve 或reject了

    })

    if(x instanceof Promise){

    运行结果:

    if(x.status == PENDING){

    once

    x.then(function(y){

    success 1005

    resolvePromise(promise2,y,resolve,reject);

    success 1007

    },reject);

    批注:promise 的 .then 或许 .catch 可以被调用数次,但那边 Promise 结构函数只进行壹回。或然说 promise 内部原因黄金时代经济体改换,况且有了三个值,那么继续每一遍调用 .then 恐怕 .catch 都会直接获得该值。

    }else{

    题目六

    x.then(resolve,reject);

    Promise.resolve()

    }

      .then(() => {

    //x是三个thenable对象或函数,只要有then方法的目的,

        return new Error('error!!!')

    }else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){

      })

    //当大家的promise和其他promise进行相互作用,编写这段代码的时候尽量的假造包容性,允许外人瞎写

      .then((res) => {

    try{

        console.log('then: ', res)

    let then = x.then;

      })

    if(typeof then == 'function'){

      .catch((err) => {

    //有些promise会同期实践成功和停业的回调

        console.log('catch: ', err)

    then.call(x,function(y){

      })

    //假诺promise2已经打响或破产了,则不会再管理了

    运维结果:

    if(called)return;

    then: Error: error!!!

    called = true;

        at Promise.resolve.then (...)

    resolvePromise(promise2,y,resolve,reject)

        at ...

    },function(err){

    解说:.then 或许 .catch 中 return 二个 error 对象并不会抛出荒诞,所以不会被延续的 .catch 捕获,必要改成当中后生可畏种:

    if(called)return;

    return Promise.reject(new Error('error!!!'))

    流程控制,异步流程控制。called = true;

    throw new Error('error!!!')

    reject(err);

    因为重返大肆一个非 promise 的值都会被卷入成 promise 对象,即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))。

    });

    题目七

    }else{

    const promise = Promise.resolve()

    //到此的话x不是贰个thenable对象,那直接把它当成值resolve promise2就足以了

      .then(() => {

    resolve(x);

        return promise

    }

      })

    }catch(e){

    promise.catch(console.error)

    if(called)return;

    运营结果:

    called = true;

    TypeError: Chaining cycle detected for promise #<Promise>

    reject(e);

        at <anonymous>

    }

        at process._tickCallback (internal/process/next_tick.js:188:7)

    }else{

        at Function.Module.runMain (module.js:667:11)

    //要是X是二个普通 的值,则用x的值去resolve promise2

        at startup (bootstrap_node.js:187:16)

    resolve(x);

        at bootstrap_node.js:607:3

    }

    表达:.then 或 .catch 再次来到的值不能够是 promise 本人,不然会招致死循环。相通于:

    }

    process.nextTick(function tick () {

    //onFulfilled 是用来抽取promise成功的值也许失利的原由

      console.log('tick')

    Promise.prototype.then = function(onFulfilled,onRejected){

    流程控制,异步流程控制。  process.nextTick(tick)

    //假使成功和曲折的回调未有传,则表示那一个then未有别的逻辑,只会把值将来抛

    })

    //2.2.1

    题目八

    onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){returnvalue};

    Promise.resolve(1)

    onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};

      .then(2)

    //假如当前promise状态已然是打响态了,onFulfilled直接取值

      .then(Promise.resolve(3))

    let self = this;

      .then(console.log)

    let promise2;

    运维结果:

    if(self.status == FULFILLED){

    1

    return promise2 = new Promise(function(resolve,reject){

    表明:.then 恐怕 .catch 的参数期待是函数,传入非函数则会发生值穿透。

    setTimeout(function(){

    题目九

    try{

    Promise.resolve()

    let x =onFulfilled(self.value);

      .then(function success (res) {

    //假若获得到了回去值x,会走剖判promise的进度

        throw new Error('error')

    resolvePromise(promise2,x,resolve,reject);

      }, function fail1 (e) {

    }catch(e){

        console.error('fail1: ', e)

    //如若施行成功的回调进度中失误了,用错误原因把promise2 reject

      })

    reject(e);

      .catch(function fail2 (e) {

    }

        console.error('fail2: ', e)

    })

      })

    });

    运作结果:

    }

    fail2: Error: error

    if(self.status == REJECTED){

        at success (...)

    return promise2 = new Promise(function(resolve,reject){

        at ...

    setTimeout(function(){

    演讲:.then 能够摄取三个参数,第贰个是拍卖成功的函数,第二个是管理错误的函数。.catch 是 .then 第4个参数的便捷写法,可是它们用法上有一些内需留意:.then 的第一个处理错误的函数捕获不了第多个管理成功的函数抛出的大谬否则,而三番捌回的 .catch 能够捕获从前的错误。当然以下代码也足以:

    try{

    Promise.resolve()

    let x =onRejected(self.value);

      .then(function success1 (res) {

    resolvePromise(promise2,x,resolve,reject);

        throw new Error('error')

    }catch(e){

      }, function fail1 (e) {

    reject(e);

        console.error('fail1: ', e)

    }

      })

    })

      .then(function success2 (res) {

    });

      }, function fail2 (e) {

    }

        console.error('fail2: ', e)

    if(self.status == PENDING){

      })

    return promise2 = new Promise(function(resolve,reject){

    题目十

    self.onResolvedCallbacks.push(function(){

    process.nextTick(() => {

    try{

      console.log('nextTick')

    let x =onFulfilled(self.value);

    })

    //假诺得到到了回来值x,会走剖判promise的历程

    Promise.resolve()

    resolvePromise(promise2,x,resolve,reject);

      .then(() => {

    }catch(e){

        console.log('then')

    reject(e);

      })

    }

    setImmediate(() => {

    });

      console.log('setImmediate')

    self.onRejectedCallbacks.push(function(){

    })

    try{

    console.log('end')

    let x =onRejected(self.value);

    运营结果:

    resolvePromise(promise2,x,resolve,reject);

    end

    }catch(e){

    nextTick

    reject(e);

    then

    }

    setImmediate

    });

    演说:process.nextTick 和 promise.then 都归属 microtask,而 setImmediate 归属 macrotask,在事件循环的 check 阶段奉行。事件循环的每一个阶段(macrotask)之间都会实践microtask,事件循环的开头会先实践壹次 microtask。

    });

    }

    }

    //catch原理正是只传失利的回调

    Promise.prototype.catch = function(onRejected){

    this.then(null,onRejected);

    }

    Promise.deferred = Promise.defer = function(){

    let defer = {};

    defer.promise = new Promise(function(resolve,reject){

    defer.resolve = resolve;

    defer.reject = reject;

    });

    return defer;

    }

    function gen(times,cb){

    let result = [],count=0;

    return function(i,data){

    result[i] = data;

    if( count==times){

    cb(result);

    }

    }

    }

    Promise.all = function(promises){

    return new Promise(function(resolve,reject){

    let done = gen(promises.length,resolve);

    for(let i=0;i<promises.length;i ){

    promises[i].then(function(data){

    done(i,data);

    },reject);

    }

    });

    }

    Promise.race = function(promises){

    return new Promise(function(resolve,reject){

    for(let i=0;i<promises.length;i ){

    promises[i].then(resolve,reject);

    }

    });

    }

    //再次回到多个当即成功的promise

    //外人提须求您二个措施,需求你传入二个promise,但您独有一个兴致索然的值,你就足以通过那么些主意把那个普通的值(string number object卡塔尔转成一个promise对象

    Promise.resolve = function(value){

    return new Promise(function(resolve){

    resolve(value);

    });

    }

    //重返叁个任何时候失利的promise

    Promise.reject = function(reason){

    return new Promise(function(resolve,reject){

    reject(reason);

    });

    }

    module.exports = Promise;

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:流程控制,异步流程控制

    关键词: