async 订阅
Async
信息
操作系统
未知
开发语言
开源协议
未知
Async
This plugin allows to easily code very long-lasting loops in an asynchronous way to avoid losing the browser responsiveness.
收起全文
精华内容
参与话题
问答
  • async

    千次阅读 2019-08-07 22:41:00
    async是什么? 说白了就是Generator的语法糖 把*换成async,把yield换成await罢了 //Generator写法 const gen = function* () { const f1 = yield readFile('/etc/fstab'); const f2 = yield readFile('/etc/...
        

    async是什么?
    说白了就是Generator的语法糖
    *换成async,把yield换成await罢了

    //Generator写法
    const gen = function* () {
      const f1 = yield readFile('/etc/fstab');
      const f2 = yield readFile('/etc/shells');
      console.log(f1.toString());
      console.log(f2.toString());
    };
    
    //async写法
    const asyncReadFile = async function () {
      const f1 = await readFile('/etc/fstab');
      const f2 = await readFile('/etc/shells');
      console.log(f1.toString());
      console.log(f2.toString());
    };
    

    但他还是有可取之处的

    • 内置执行器
      async函数的执行像普通函数一样,只需要一个括号即可asyncReadFile()不像Generator,需要迭代器,调用next方法才可以执行

    • 更好的语义
      asyncawait,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

    • 更广的适用性。
      co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolvedPromise 对象)。

    • 返回值是 Promise
      async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

    进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

    基本用法

    async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

    下面是一个例子。

    async function getStockPriceByName(name) {
      const symbol = await getStockSymbol(name);
      const stockPrice = await getStockPrice(symbol);
      return stockPrice;
    }
    
    getStockPriceByName('goog').then(function (result) {
      console.log(result);
    });
    

    async 函数有多种使用形式。

    // 函数声明
    async function foo() {}
    
    // 函数表达式
    const foo = async function () {};
    
    // 对象的方法
    let obj = { async foo() {} };
    obj.foo().then(...)
    
    // Class 的方法
    class Storage {
      constructor() {
        this.cachePromise = caches.open('avatars');
      }
    
      async getAvatar(name) {
        const cache = await this.cachePromise;
        return cache.match(`/avatars/${name}.jpg`);
      }
    }
    
    const storage = new Storage();
    storage.getAvatar('jake').then(…);
    
    // 箭头函数
    const foo = async () => {};
    

    语法

    返回 Promise 对象

    async函数返回一个 Promise 对象。

    async函数内部return语句返回的值,会成为then方法回调函数的参数。

    async function f() {
      return 'hello world';
    }
    
    f().then(v => console.log(v))
    // "hello world"
    

    async函数内部抛出错误,会导致返回的 Promise对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

    Promise 对象的状态变化

    async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

    下面是一个例子。

    async function getTitle(url) {
      let response = await fetch(url);
      let html = await response.text();
      return html.match(/<title>([\s\S]+)<\/title>/i)[1];
    }
    getTitle('https://tc39.github.io/ecma262/').then(console.log)
    // "ECMAScript 2017 Language Specification"
    

    上面代码中,函数getTitle内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行then方法里面的console.log。

    await命令

    正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

    async function f() {
      // 等同于
      // return 123;
      return await 123;
    }
    
    f().then(v => console.log(v))
    // 123
    

    上面代码中,await命令的参数是数值123,这时等同于return 123。

    另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。

    class Sleep {
      constructor(timeout) {
        this.timeout = timeout;
      }
      then(resolve, reject) {
        const startTime = Date.now();
        setTimeout(
          () => resolve(Date.now() - startTime),
          this.timeout
        );
      }
    }
    
    (async () => {
      const sleepTime = await new Sleep(1000);
      console.log(sleepTime);
    })();
    // 1000
    

    上面代码中,await命令后面是一个Sleep对象的实例。这个实例不是 Promise 对象,但是因为定义了then方法,await会将其视为Promise处理。

    这个例子还演示了如何实现休眠效果。JavaScript 一直没有休眠的语法,但是借助await命令就可以让程序停顿指定的时间。

    function sleep(interval) {
      return new Promise(resolve => {
        setTimeout(resolve, interval);
      })
    }
    
    // 用法
    async function one2FiveInAsync() {
      for(let i = 1; i <= 5; i++) {
        console.log(i);
        await sleep(1000);
      }
    }
    
    one2FiveInAsync();
    

    其中for循环也会延缓执行
    await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。

    任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

    async function f() {
      await Promise.reject('出错了');
      await Promise.resolve('hello world'); // 不会执行
    }
    

    有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。
    另一种方法是await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误。

    async function f() {
      await Promise.reject('出错了')
        .catch(e => console.log(e));
      return await Promise.resolve('hello world');
    }
    
    f()
    .then(v => console.log(v))
    // 出错了
    // hello world
    
    注意点
    • await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
    async function myFunction() {
      try {
        await somethingThatReturnsAPromise();
      } catch (err) {
        console.log(err);
      }
    }
    
    // 另一种写法
    
    async function myFunction() {
      await somethingThatReturnsAPromise()
      .catch(function (err) {
        console.log(err);
      });
    }
    
    • 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
    // 写法一
    let [foo, bar] = await Promise.all([getFoo(), getBar()]);
    
    // 写法二
    let fooPromise = getFoo();
    let barPromise = getBar();
    let foo = await fooPromise;
    let bar = await barPromise;
    
    • await命令只能用在async函数之中,如果用在普通函数,就会报错。
      有时把普通函数改写成async函数也会报错。比如forEach
    function dbFuc(db) { //这里不需要 async
      let docs = [{}, {}, {}];
    
      // 可能得到错误结果
      docs.forEach(async function (doc) {
        await db.post(doc);
      });
    }
    

    上面代码可能不会正常工作,原因是这时三个db.post操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用for循环。

    async function dbFuc(db) {
      let docs = [{}, {}, {}];
    
      for (let doc of docs) {
        await db.post(doc);
      }
    }
    
    • async 函数可以保留运行堆栈。
    const a = () => {
      b().then(() => c());
    };
    

    上面代码中,函数a内部运行了一个异步任务b()。当b()运行的时候,函数a()不会中断,而是继续执行。等到b()运行结束,可能a()早就运行结束了,b()所在的上下文环境已经消失了。如果b()或c()报错,错误堆栈将不包括a()。

    现在将这个例子改成async函数。

    const a = async () => {
      await b();
      c();
    };
    
    async函数的实现原理

    将 Generator 函数和自动执行器,包装在一个函数里。
    手写await?

    function spawn(genF) {
      return new Promise(function(resolve, reject) {
        const gen = genF();
        function step(nextF) {
          let next;
          try {
            next = nextF();
          } catch(e) {
            return reject(e);
          }
          if(next.done) {
            return resolve(next.value);
          }
          Promise.resolve(next.value).then(function(v) {
            step(function() { return gen.next(v); });
          }, function(e) {
            step(function() { return gen.throw(e); });
          });
        }
        step(function() { return gen.next(undefined); });
      });
    }
    
    异步加载模块
    // awaiting.js
    const dynamic = import(someMission);
    const data = fetch(url);
    export const output = someProcess((await dynamic).default, await data);
    

    上面代码中,两个异步操作在输出的时候,都加上了await命令。只有等到异步操作完成,这个模块才会输出值。

    加载这个模块的写法如下。

    // usage.js
    import { output } from "./awaiting.js";
    function outputPlusValue(value) { return output + value }
    
    console.log(outputPlusValue(100));
    setTimeout(() => console.log(outputPlusValue(100), 1000);
    
    展开全文
  • Async

    2018-03-26 16:09:26
    ECMAScript 2017 Async Functions(异步函数)。 今天被萌神鄙视了说我写的blog丑所以我就开始用markdown学习并且使用markdown开始写一篇文章试下 async各种不同的定义方式 异步函数声明: async ...

    ECMAScript 2017 Async Functions(异步函数)。


    ##今天被萌神鄙视了说我写的blog丑所以我就开始用markdown学习并且使用markdown开始写一篇文章试下

    ###async各种不同的定义方式
    异步函数声明: async function foo() {}
    异步函数表达式: const foo = async function () {};
    异步函数定义:let obj = { async foo() {} }
    异步箭头函数: const foo = async () => {};

    ###async(异步) 函数总是返回 Promises

    async(异步) 函数的 Promise 完成状态:

    async function asyncFunc() {
        return 123;
    }
     
    asyncFunc()
    .then(x => console.log(x));
        // 123
    

    async(异步) 函数的 Promise 拒绝状态:

    async function asyncFunc() {
        throw new Error('Problem!');
    }
     
    asyncFunc()
    .catch(err => console.log(err));
        // Error: Problem!
    

    ###通过 await 处理 async(异步) 计算的结果和错误

    await(只允许在 async(异步) 函数内部使用)等待其操作对象 Promise返回

    • 如果 Promise 是完成状态,await 的结果是完成态的值。
    • 如果 Promise 是拒绝状态,await 会抛出拒绝值。

    处理单个 async(异步) 返回值:

    async function asyncFunc() {
        const result = await otherAsyncFunc();
        console.log(result);
    }
     
    // 等价于:
    function asyncFunc() {
        return otherAsyncFunc()
        .then(result => {
            console.log(result);
        });
    }
    

    按顺序处理多个 async(异步) 返回值

    async function asyncFunc() {
        const result1 = await otherAsyncFunc1();
        console.log(result1);
        const result2 = await otherAsyncFunc2();
        console.log(result2);
    }
     
    // 等价于:
    function asyncFunc() {
        return otherAsyncFunc1()
        .then(result1 => {
            console.log(result1);
            return otherAsyncFunc2();
        })
        .then(result2 => {
            console.log(result2);
        });
    }
    

    并行处理多个 async(异步) 返回值:

    async function asyncFunc() {
        const [result1, result2] = await Promise.all([
            otherAsyncFunc1(),
            otherAsyncFunc2(),
        ]);
        console.log(result1, result2);
    }
     
    // 等价于:
    function asyncFunc() {
        return Promise.all([
            otherAsyncFunc1(),
            otherAsyncFunc2(),
        ])
        .then([result1, result2] => {
            console.log(result1, result2);
        });
    }
    

    错误处理:

    async function asyncFunc() {
        try {
            await otherAsyncFunc();
        } catch (err) {
            console.error(err);
        }
    }
     
    // 等价于:
    function asyncFunc() {
        return otherAsyncFunc()
        .catch(err => {
            console.error(err);
        });
    }
    

    ##理解 async(异步) 函数
    在我解释 async(异步) 函数之前,我需要解释一下如何组合使用 Promises 和 Generator ,通过看起来同步的代码来执行 async(异步) 操作。

    对于能够 async(异步) 计算其一次性结果的函数,作为 ES6 一部分的 Promises 已经变得流行起来。一个例子是 客户端 fetch API ,它是 XMLHttpRequest 获取数据的替代方法。使用示例如下:

    function fetchJson(url) {
        return fetch(url)
        .then(request => request.text())
        .then(text => {
            return JSON.parse(text);
        })
        .catch(error => {
            console.log(`ERROR: ${error.stack}`);
        });
    }
    fetchJson('http://example.com/some_file.json')
    .then(obj => console.log(obj));
    

    ###通过 generator 来编写异步代码
    co 是一个使用 Promise 和 generator 来实现看似同步编码的库,但与上一示例中使用的样式相同:

    const fetchJson = co.wrap(function* (url) {
        try {
            let request = yield fetch(url);
            let text = yield request.text();
            return JSON.parse(text);
        }
        catch (error) {
            console.log(`ERROR: ${error.stack}`);
        }
    });
    

    每次回调函数( generator 函数)产生一个 Promise 对象给 co ,回调会被暂停,只有当 Promise 执行完成后,co 才会继续执行回调 。 如果 Promise 处于完成状态,yield 返回完成状态的值,如果处于拒绝状态,yield 抛出拒绝状态的错误。此外,co 保证结果是通过回调执行完成才返回的(类似于 then() 所做的工作)。
    ###通过 async(异步) 函数来编写异步代码
    async(异步) 函数用的特定语法基本上和 co 类似:

    async function fetchJson(url) {
        try {
            let request = await fetch(url);
            let text = await request.text();
            return JSON.parse(text);
        }
        catch (error) {
            console.log(`ERROR: ${error.stack}`);
        }
    }
    

    在内部,异步函数写法更类似于 generators
    ###以同步开始,异步处理的 async(异步) 函数

    以下是 async(异步)函数是如何工作的:

    • async(异步) 函数总是返回一个 Promise 对象 p 。Promise 对象在 async(异步) 函数开始执行时被创建
    • 函数体执行过程中,可以通过可以通过 return 或 throw 终止执行。或者通过 await 暂停执行,在这种情况下,通常会在以后继续执行。
    • 返回 Promise 对象 p。

    当执行 async(异步) 函数的函数体时,return x 中的 x 是 Promise 对象 p 的完成状态的结果,而 throw err 是 p 的拒绝状态的结果。执行结果是异步返回的。换句话说:then() 和 catch() 的回调总是在当前代码完成后执行。

    以下是代码示例:

    async function asyncFunc() {
        console.log('asyncFunc()'); // (A)
        return 'abc';
    }
    asyncFunc().
    then(x => console.log(`Resolved: ${x}`)); // (B)
    console.log('main'); // (C)
     
    // Output:
    // asyncFunc()
    // main
    // Resolved: abc
    
    • 行A:async(异步) 函数以同步开始。async(异步) 函数的 Promise 通过 return 来返回完成状态的结果。
    • 行C:执行继续。
    • 行B:Promise 完成状态通知是异步发生的。

    ###返回不被包裹的 Promise 对象
    Promise 的 resolve 是一项标准操作。 return 就是使用它来 resolve async(异步) 函数的 Promise p 的。这意味着:

    • 返回一个非 Promise 值,该值将被处理成 p 的完成状态值。
    • 返回一个 Promise 对象,那么 p 此时相当于是该 Promise 的状态。

      因此,您可以返回一个 Promise ,并且这个 Promise 不会包裹在别的 Promise 中:
    async function asyncFunc() {
        return Promise.resolve(123);
    }
    asyncFunc()
    .then(x => console.log(x)) // 123
    

    有趣的是,返回一个拒绝状态(reject)的 Promise 对象会导致 async(异步) 函数被拒绝(reject)(通常,您可以使用 throw ):

    async function asyncFunc() {
        return Promise.reject(new Error('Problem!'));
    }
    asyncFunc()
    .catch(err => console.error(err)); // Error: Problem!
    

    这与 Promise 解决方案的工作方式是一致的。 使你能够在不使用 await 的情况下,使用其他 async(异步) 计算来执行完成和拒绝处理:

    async function asyncFunc() {
        return anotherAsyncFunc();
    }
    

    上面的代码示例和下面的类似,但是比下面的更高效。(以下代码示例没有包裹 anotherAsyncFunc() 的 Promise ,而是包裹 anotherAsyncFunc() 本身 ):

    async function asyncFunc() {
        return await anotherAsyncFunc();
    }
    

    ###await 是顺序执行的,Promise.all() 是并行的
    下面的代码调用了两个 async(异步) 函数, asyncFunc1() 和 asyncFunc1() 。

    async function foo() {
        const result1 = await asyncFunc1();
        const result2 = await asyncFunc2();
    }
    

    这两个函数调用顺序执行。但是并行执行它们往往会加快速度。您可以使用 Promise.all()

    async function foo() {
        const [result1, result2] = await Promise.all([
            asyncFunc1(),
            asyncFunc2(),
        ]);
    }
    

    我们现在正在等待一个包含两个元素的数组的 Promise ,而不是等待两个 Promise。
    ###异步函数和回调
    async(异步) 函数的一个限制是 await(等待) 只影响直接相关的 async(异步) 函数。因此,async(异步) 函数无法在回调(但是,回调可以是 async(异步) 函数本身,稍后我们将会看到)中使用 await(等待)。这使得基于回调的实用函数和方法难以使用。例子中我们将使用数组方法 map() 和 forEach() 。
    ####Array.prototype.map()
    ####Array.prototype.forEach()

    ###了解你的 Promises
    async(异步) 函数的基础就是 Promises 对象,这就是为什么理解 Promises 对于理解 async(异步) 函数至关重要。特别是当遇到不是基于 Promises 的老代码来实现 async(异步) 函数时,你通常别无选择,只能用 Promise 来重构。

    举个例子,这里有个 “promisified” 版本的XMLHttpRequest

    function httpGet(url, responseType="") {
        return new Promise(
            function (resolve, reject) {
                const request = new XMLHttpRequest();
                request.onload = function () {
                    if (this.status === 200) {
                        // Success
                        resolve(this.response);
                    } else {
                        // Something went wrong (404 etc.)
                        reject(new Error(this.statusText));
                    }
                };
                request.onerror = function () {
                    reject(new Error(
                        'XMLHttpRequest Error: '+this.statusText));
                };
                request.open('GET', url);
                xhr.responseType = responseType;
                request.send();
            });
    }
    

    XMLHttpRequest 的 API 是基于回调的。通过一个 async(异步) 函数来实现它,意味着你必须在回调中返回 Promise 的完成(fulfill) 或拒绝(reject) 状态。这是不可能的,因为你只能通过 return 或者 throw 来完成这样的操作。你不能从回调函数内部 return 一个函数的结果。throw也有类似的约束。
    因此,异步函数的通用编码风格是:

    • 直接使用 Promise 对象来构建异步原语。
    • 用异步函数来使用这些原语。

    http://www.css88.com/archives/7731

    展开全文
  • 使用ES6新特性async await进行异步处理

    万次阅读 多人点赞 2018-07-12 15:56:30
    我们往往在项目中会遇到这样的业务需求,就是首先...那是相当恶心的,下面我就来讲一下如何使用ES6的新特性async await进行异步处理,使上述情况就好像写同步代码一样,首先我们先举个例子: 先写上json文件: cod...

    我们往往在项目中会遇到这样的业务需求,就是首先先进行一个ajax请求,然后再进行下一个ajax请求,而下一个请求需要使用上一个请求得到的数据,请求少了还好说,如果多了,就要一层一层的嵌套,就好像有点callback的写法了,那是相当恶心的,下面我就来讲一下如何使用ES6的新特性async await进行异步处理,使上述情况就好像写同步代码一样,首先我们先举个例子:
    先写上json文件:
    code.json:

    {
        "code":0,
        "msg":"成功"
    }
    

    person.json:

    {
        "code":0,
        "list":[
            {
                "id":1,
                "name":"唐僧"
            },
            {
                "id":2,
                "name":"孙悟空"
            },
            {
                "id":3,
                "name":"猪八戒"
            },
            {
                "id":4,
                "name":"沙僧"
            }
        ]
    }
    

    比如我们有两个请求,如下,这里用的axios:

     function getCode(){
          return axios.get('json/code.json');
      }
     function getlist(params){
          return axios.get('json/person.json',{params})
      }
    

    我们第二个请求获取列表的时候需要使用第一个请求得到的code值,只有code值为0时,才能请求,而且当做参数传进去,那么我们看一下常规的做法吧

    function getFinal(){
    	  console.log("我是getFinal函数")
          getCode().then(function(res){
             if(res.data.code == 0){
                   console.log(res.data.code);
                     var params = {
                          code:res.data.code
                      }
                   getlist(params).then(function(res){
                        if(res.data.code == 0){
                             console.log(res.data.list);
                           }
                       })
                    }
              })
          }
      getFinal();
    

    看结果
    这里写图片描述
    虽然结果出来了,可是这种写法真的挺难受的,下面来一个async await的写法

    async function getResult(){
                console.log("我是getResult函数")
                let code = await getCode();
                console.log(code.data.code);
                if(code.data.code == 0){
                    var params = {
                        code:code.data.code
                    }
                    let list = await getlist(params);
                    console.log(list.data.list);
                }
            }
    getResult();
    

    下面看结果
    这里写图片描述
    当然还剩最后一点,处理异常,可以加上try catch

    async function getResult(){
                console.log("我是getResult函数")
                try{
    				let code = await getCode();
    	            console.log(code.data.code);
    	            if(code.data.code == 0){
    	                var params = {
    	                    code:code.data.code
    	                }
    	                let list = await getlist(params);
    	                console.log(list.data.list);
    	            }
    			}catch(err){
    				console.log(err);
    			}
            }
    getResult();
    

    个人认为做vue项目的时候,如果对于异常没有特殊处理,可以不加try catch,因为打印出来的错误跟vue自己报的错误是一样的,而且还是黑的字体,不如醒目的红色来的痛快啊!当然如果要对错误进行特殊处理,那么就加上吧

    代码风格是不是简便了许多,而且异步代码变成了同步代码,下面我稍微讲一下后者写法的代码执行顺序

    首先在 function 前面加 async 用来说明这个函数是一个异步函数,当然,async是要和await配合使用的,第一个请求

    let code = await getCode();
    

    await 意思是等一下,等着getCode()这个函数执行完毕,得到值后再赋值给code,然后再用code的值进行下一步操作,就是这么简单!!!赶紧去改代码!!

    展开全文
  • Async 详解

    万次阅读 2019-03-24 10:45:54
    最终觉得还是async最靠谱。 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种常见流程的处理 集合处理:如何使用异步操作处理集合中的数据 工具类:几个常用的工具类 本文...

    一:流程控制

    为了适应异步编程,减少回调的嵌套,我尝试了很多库。最终觉得还是async最靠谱。

    地址:https://github.com/caolan/async

    Async的内容分为三部分:

    1. 流程控制:简化十种常见流程的处理
    2. 集合处理:如何使用异步操作处理集合中的数据
    3. 工具类:几个常用的工具类

    本文介绍其中最简单最常用的流程控制部分。

    由于nodejs是异步编程模型,有一些在同步编程中很容易做到的事情,现在却变得很麻烦。Async的流程控制就是为了简化这些操作。

    1. series(tasks, [callback]) (多个函数依次执行,之间没有数据交换)

    有多个异步函数需要依次调用,一个完成之后才能执行下一个。各函数之间没有数据的交换,仅仅需要保证其执行顺序。这时可使用series。

    纯js代码:

    step1(function(err, v1) { step2(function(err, v2) { step3(function(err, v3) { // do somethig with the err or values v1/v2/v3 } } });

    从中可以看到这嵌套还是比较多深的,如果再多几步,会更深。在代码中忽略对了每一层err的处理,否则还都等加上 if(err) return callback(err),那就更麻烦了。

    对于这种情况,使用async来处理,就是这样的:

    var async = require('async') async.series([ step1, step2, step3 ], function(err, values) { // do somethig with the err or values v1/v2/v3 });

    可以看到代码简洁了很多,而且自动处理每个回调中的错误。当然,这里只给出来最最简单的例子,在实际中,我们常会在每个step中执行一些操作,这时可写成:

    var async = require('async') async.series([ function(cb) { step1(function(err,v1) { // do something with v1 cb(err, v1); }), function(cb) { step2(...) }, function(cb) { step3(...) } ], function(err, values) { // do somethig with the err or values v1/v2/v3 });

    该函数的详细解释为:

    1. 依次执行一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数。
    2. 如果任何一个函数向它的回调函数中传了一个error,则后面的函数都不会被执行,并且将会立刻会将该error以及已经执行了的函数的结果,传给series中最后那个callback。
    3. 当所有的函数执行完后(没有出错),则会把每个函数传给其回调函数的结果合并为一个数组,传给series最后的那个callback。
    4. 还可以json的形式来提供tasks。每一个属性都会被当作函数来执行,并且结果也会以json形式传给series最后的那个callback。这种方式可读性更高一些。

    具体例子可参考:https://github.com/freewind/async_demo/blob/master/series.js

    其代码中还包含了:

    1. 如果中间某个函数出错,series函数如何处理
    2. 如果某个函数传给回调的值为undefined, null, {}, []等,series如何处理

    另外还需要注意的是:多个series调用之间是不分先后的,因为series本身也是异步调用。

    2. parallel(tasks, [callback]) (多个函数并行执行)

    并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。

    如果某个函数出错,则立刻将err和已经执行完的函数的结果值传给parallel最终的callback。其它未执行完的函数的值不会传到最终数据,但要占个位置。

    同时支持json形式的tasks,其最终callback的结果也为json形式。

    示例代码:

    async.parallel([ function(cb) { t.fire('a400', cb, 400) }, function(cb) { t.fire('a200', cb, 200) }, function(cb) { t.fire('a300', cb, 300) } ], function (err, results) { log('1.1 err: ', err); // -> undefined log('1.1 results: ', results); // ->[ 'a400', 'a200', 'a300' ] });

    中途出错的示例:

    async.parallel([ function(cb) { log('1.2.1: ', 'start'); t.fire('a400', cb, 400) }, // 该函数的值不会传给最终callback,但要占个位置 function(cb) { log('1.2.2: ', 'start'); t.err('e200', cb, 200) }, function(cb) { log('1.2.3: ', 'start'); t.fire('a100', cb, 100) } ], function(err, results) { log('1.2 err: ', err); // -> e200 log('1.2 results: ', results); // -> [ , undefined, 'a100' ] });

    以json形式传入tasks

    async.parallel({ a: function(cb) { t.fire('a400', cb, 400) }, b: function(cb) { t.fire('c300', cb, 300) } }, function(err, results) { log('1.3 err: ', err); // -> undefined log('1.3 results: ', results); // -> { b: 'c300', a: 'a400' } });

    更详细示例参见:https://github.com/freewind/async_demo/blob/master/parallel.js

    3. waterfall(tasks, [callback]) (多个函数依次执行,且前一个的输出为后一个的输入)

    与seires相似,按顺序依次执行多个函数。不同之处,每一个函数产生的值,都将传给下一个函数。如果中途出错,后面的函数将不会被执行。错误信息以及之前产生的结果,将传给waterfall最终的callback。

    这个函数名为waterfall(瀑布),可以想像瀑布从上到下,中途冲过一层层突起的石头。注意,该函数不支持json格式的tasks。

    async.waterfall([ function(cb) { log('1.1.1: ', 'start'); cb(null, 3); }, function(n, cb) { log('1.1.2: ',n); t.inc(n, cb); }, function(n, cb) { log('1.1.3: ',n); t.fire(n*n, cb); } ], function (err, result) { log('1.1 err: ', err); // -> null log('1.1 result: ', result); // -> 16 });

    更详细示例参见:https://github.com/freewind/async_demo/blob/master/waterfall.js

    4. auto(tasks, [callback]) (多个函数有依赖关系,有的并行执行,有的依次执行)

    用来处理有依赖关系的多个任务的执行。比如某些任务之间彼此独立,可以并行执行;但某些任务依赖于其它某些任务,只能等那些任务完成后才能执行。

    虽然我们可以使用async.parallel和async.series结合起来实现该功能,但如果任务之间关系复杂,则代码会相当复杂,以后如果想添加一个新任务,也会很麻烦。这时使用async.auto,则会事半功倍。

    如果有任务中途出错,则会把该错误传给最终callback,所有任务(包括已经执行完的)产生的数据将被忽略。

    这里假设我要写一个程序,它要完成以下几件事:

    1. 从某处取得数据
    2. 在硬盘上建立一个新的目录
    3. 将数据写入到目录下某文件
    4. 发送邮件,将文件以附件形式发送给其它人。

    分析该任务,可以知道1与2可以并行执行,3需要等1和2完成,4要等3完成。

    async.auto({ getData: function (callback) { setTimeout(function(){ console.log('1.1: got data'); callback(); }, 300); }, makeFolder: function (callback) { setTimeout(function(){ console.log('1.1: made folder'); callback(); }, 200); }, writeFile: ['getData', 'makeFolder', function(callback) { setTimeout(function(){ console.log('1.1: wrote file'); callback(null, 'myfile'); }, 300); }], emailFiles: ['writeFile', function(callback, results) { log('1.1: emailed file: ', results.writeFile); // -> myfile callback(null, results.writeFile); }] }, function(err, results) { log('1.1: err: ', err); // -> null log('1.1: results: ', results); // -> { makeFolder: undefined, // getData: undefined, // writeFile: 'myfile', // emailFiles: 'myfile' } });

    更多详细示例参见:https://github.com/freewind/async_demo/blob/master/auto.js

    5. whilst(test, fn, callback)(用可于异步调用的while)

    相当于while,但其中的异步调用将在完成后才会进行下一次循环。举例如下:

    var count1 = 0; async.whilst( function() { return count1 < 3 }, function(cb) { log('1.1 count: ', count1); count1++; setTimeout(cb, 1000); }, function(err) { // 3s have passed log('1.1 err: ', err); // -> undefined } );

    它相当于:

    try { whilst(test) { fn(); } callback(); } catch (err) { callback(err); }

    该函数的功能比较简单,条件变量通常定义在外面,可供每个函数访问。在循环中,异步调用时产生的值实际上被丢弃了,因为最后那个callback只能传入错误信息。

    另外,第二个函数fn需要能接受一个函数cb,这个cb最终必须被执行,用于表示出错或正常结束。

    更详细示例参见:https://github.com/freewind/async_demo/blob/master/whilst_until.js

    6. until(test, fn, callback) (与while相似,但判断条件相反)

    var count4 = 0; async.until( function() { return count4>3 }, function(cb) { log('1.4 count: ', count4); count4++; setTimeout(cb, 200); }, function(err) { // 4s have passed log('1.4 err: ',err); // -> undefined } );

    当第一个函数条件为false时,继续执行第二个函数,否则跳出。

    7. queue (可设定worker数量的队列)

    queue相当于一个加强版的parallel,主要是限制了worker数量,不再一次性全部执行。当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。

    该函数有多个点可供回调,如worker用完时、无等候任务时、全部执行完时等。

    定义一个queue,其worker数量为2,并在任务执行时,记录一下日志:

    var q = async.queue(function(task, callback) { log('worker is processing task: ', task.name); task.run(callback); }, 2);

    worker数量将用完时,会调用saturated函数:

    q.saturated = function() { log('all workers to be used'); }

    当最后一个任务交给worker执行时,会调用empty函数

    q.empty = function() { log('no more tasks wating'); }

    当所有任务都执行完时,会调用drain函数

    q.drain = function() { console.log('all tasks have been processed'); }

    放入多个任务,可一次放一个,或一次放多个

    q.push({name:'t1', run: function(cb){ log('t1 is running, waiting tasks: ', q.length()); t.fire('t1', cb, 400); // 400ms后执行 }}, function(err) { log('t1 executed'); });

    q.push([{name:'t3', run: function(cb){ log('t3 is running, waiting tasks: ', q.length()); t.fire('t3', cb, 300); // 300ms后执行 }},{name:'t4', run: function(cb){ log('t4 is running, waiting tasks: ', q.length()); t.fire('t4', cb, 500); // 500ms后执行 }}], function(err) { log('t3/4 executed'); });

    更多详细示例参见:https://github.com/freewind/async_demo/blob/master/queue.js

    8. iterator(tasks) (将几个函数包装为iterator)

    将一组函数包装成为一个iterator,可通过next()得到以下一个函数为起点的新的iterator。该函数通常由async在内部使用,但如果需要时,也可在我们的代码中使用它。

    var iter = async.iterator([ function() { console.log('111') }, function() { console.log('222') }, function() { console.log('333') } ]); console.log(iter()); console.log(iter.next());

    直接调用(),会执行当前函数,并返回一个由下个函数为起点的新的iterator。调用next(),不会执行当前函数,直接返回由下个函数为起点的新iterator。

    对于同一个iterator,多次调用next(),不会影响自己。如果只剩下一个元素,调用next()会返回null。

    更详细示例参见:https://github.com/freewind/async_demo/blob/master/iterator.js

    9. apply(function, arguments..) (给函数预绑定参数)

    apply是一个非常好用的函数,可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代码。

    对于函数:

    function(callback) { t.inc(3, callback); }

    可以用apply改写为:

    async.apply(t.inc, 3);

    还可以给某些函数预设值,得到一个新函数:

    var log = async.apply(console.log, ">"); log('hello'); // > hello

    更详细代码参见:https://github.com/freewind/async_demo/blob/master/apply.js

    10. nextTick(callback) (在nodejs与浏览器两边行为一致)

    nextTick的作用与nodejs的nextTick一样,都是把某个函数调用放在队列的尾部。但在浏览器端,只能使用setTimeout(callback,0),但这个方法有时候会让其它高优先级的任务插到前面去。

    所以提供了这个nextTick,让同样的代码在服务器端和浏览器端表现一致。

    var calls = []; async.nextTick(function() { calls.push('two'); }); calls.push('one'); async.nextTick(function() { console.log(calls); // -> [ 'one', 'two' ] });

    更详细代码参见:https://github.com/freewind/async_demo/blob/master/nextTick.js

     

    二:工具类

    Async中提供了几个工具类,给我们提供一些小便利:

    1. memoize
    2. unmemoize
    3. log
    4. dir
    5. noConflict

    1. memoize(fn, [hasher])

    有一些方法比较耗时,且对于相同的输入总是有相同的输出。这时可以使用memoize给它加个缓存,对于相同的参数只计算一次,以后就直接从缓存中取结果用了。

    比如这里有一个很慢的函数:

    var slow_fn = function(x, y, callback) { 

        console.log(‘start working for: ‘ + x+’,'+y); 

        t.wait(100); 

        console.log(‘finished: ‘ + x+’,'+y); 

        callback(null, ‘im slow for: ‘+x+’,'+y); 

    };

    可以用memoize生成一个新的带缓存的函数:

    var fn = async.memoize(slow_fn);

    试试同样参数调用两次:

    fn(‘a’,'b’, function(err, result) { 

        console.log(result); 

    });

    // 直接得到之前计算好的值 

    fn(‘a’,'b’, function(err, result) { 

        console.log(result); 

    });

     

    注意memoize的参数中还有一个hasher,它是做什么用的呢?它可以让我们自定义如果根据参数来判断是否从缓存中取。默认情况下,两次调用,只有参数完全一样的时候才会从缓存中取。这里我们使用hasher来改变规则。

    var fn_hasher = async.memoize(slow_fn, function(x,y) { 

        return x+y; 

    });

     

    新定义的这个,将根据两个参数的和来判断。

    fn_hasher(‘cd’,'e’, function(err, result) { 

        console.log(result); 

    });

    fn_hasher(‘c’,'de’, function(err, result) { 

        console.log(result); // 可以取得前面(‘cd’,'e’)的计算结果 

                             // im show for: cd,e 

    });

     

    第二次的调用,虽然参数跟第一次不一样,但是其和却一样,所以直接从缓存中拿到前次运行结果。

    2. unmemoize(fn)

    unmemoize的作用正好跟memoize相反,它可以把一个带缓存的函数再变回原样:

    var fn2 = async.unmemoize(fn); 

    console.log(‘unmemoized’);

    fn2(‘a’,'b’, function(err,result) { 

        console.log(result); 

    });

     

    经过unmemoize后,再运行该函数就得重新运算了。

    3. log(function, arguments)

    log用于快速执行某异步函数,并记录它的返回值。试验函数时很方便,不用写那些固定模式的代码。

    var x = function() { 

        this.name = ‘Freewind’; 

    var hello = function(name, callback) { 

        setTimeout(function() { 

            callback(null, ‘hello ‘ + name, ‘nice to see you ‘ + name, x, {a:’123′}); 

        }, 200); 

    };

    async.log(hello, ‘world’);

    打印结果如下:

    hello world 

    nice to see you world 

    [Function] 

    { a: ’123′ }

    可以看到,它直接运行了该函数,并以每行一个参数的形式打印出了结果。

    4. dir(function, arguments)

    该函数与log非常像,不同之处在于,它最终调用了console.dir,而log最终调用了console.log。

    看看使用dir打印的效果如何:

    async.dir(hello, ‘world’);

    结果:

    ‘hello world’ 

    ‘nice to see you world’ 

    [Function] 

    { a: ’123′ }

    仅仅是多了几个单引号。为了弄清楚dir存在的意义(什么情况下应该使用dir而不是log),我提了一个问题,参看:http://stackoverflow.com/questions/10636866/whats-the-difference-between-async-log-and-async-dir

    5. noConflict

    最后是这个noConflict,它仅仅用于浏览器端,在nodejs中没用,这里无法演示。

    它的作用是:如果之前已经在全局域中定义了async变量,当导入本async.js时,会先把之前的async变量保存起来,然后覆盖它。用完之后,调用noConflict()方法,就会归还该值。同时返回async本身供换名使用。

    这里可以看一下它的实现代码:

    // global on the server, window in the browser 

    var root = this, 

        previous_async = root.async;

    if (typeof module !== ‘undefined’ && module.exports) { 

        module.exports = async; 

    else { 

        root.async = async; 

    }

    async.noConflict = function () { 

        root.async = previous_async; 

        return async; 

    };

     

    可以看到,当处于nodejs或者commonjs环境中,它会执行module.exports=async,在其它情况下(通常为浏览器端)才会root.async=async,将async赋值给root。

    在浏览器中的用法如下:

    <script type="text/JavaScript" src="other_lib.js"></script> 

    <script type="text/javascript" src="async.js"></script> 

    <script type="text/javascript">

      // code using async 

      async.noConflict(); 

      // Code that uses other library’s ‘async’ can follow here. 

    </script>

    三:集合操作

    Async提供了很多针对集合的函数,可以简化我们对集合进行异步操作时的步骤。如下:

    1. forEach:对集合中每个元素进行异步操作
    2. map:对集合中的每个元素通过异步操作得到另一个值,得到新的集合
    3. filter:对集合中元素使用异步操作进行筛选,得到符合条件的集合
    4. reject:与filter相似,只是判断条件时正好相反,得到剩下的元素的集合
    5. reduce:使用一个初始值同集合中每一个元素进行异步操作,最后得到一个唯一的结果
    6. detect:得到集合中满足条件的第一个数据
    7. sortBy:对集合中的数据进行异步操作,再根据值从小到大排序
    8. some/any:集合中是否有至少一个元素满足条件
    9. every/all:集合中是否每个元素都满足条件
    10. concat:对集合中的元素进行异步操作,将结果集合并成一个数组

    下面一一解释:

    1. forEach(arr, iterator(item, callback), callback(err))

    如果想对同一个集合中的所有元素都执行同一个异步操作,可以利用forEach函数。注意该函数将重点放在“执行过程”上,忽略运行后产生的数据。如果需要结果,可使用map函数。

    根据执行的方式不同,forEach提供了三个版本:

    1. 集合中所有元素并行执行
    2. 一个一个顺序执行
    3. 分批执行,同一批内并行,批与批之间按顺序

    首先看并行执行的例子,它比较简单,只是打印出传入的元素内容:

    var arr = [{name:'Jack', delay: 200}, 

               {name:'Mike', delay: 100}, 

               {name:'Freewind', delay: 300}];

     

    async.forEach(arr, function(item, callback) { 

        log(’1.1 enter: ‘ + item.name); 

        setTimeout(function(){ 

            log(’1.1 handle: ‘ + item.name); 

            callback(); 

        }, item.delay); 

    }, function(err) { 

        log(’1.1 err: ‘ + err); 

    });

     

    它将打出如下结果:

    42.244> 1.1 enter: Jack 

    42.245> 1.1 enter: Mike 

    42.245> 1.1 enter: Freewind 

    42.350> 1.1 handle: Mike 

    42.445> 1.1 handle: Jack 

    42.554> 1.1 handle: Freewind 

    42.554> 1.1 err: undefined

    最前面的数据是当前的时间值(秒.毫秒),从中可以看到各异步操作是并行执行的。

    如果想同步执行,需要使用forEachSeries函数,它与forEach的用法一模一样,只是执行时是一个一个来的。这里就不给例子了。

    当集合中元素很多,既不想一次全部并行操作,又不想一个一个按顺序来,可以使用forEachLimit函数。它可以设定一批处理几个,每一批内并行执行,批与批之间顺序执行。

    async.forEachLimit(arr, 2, function(item, callback) { 

        log(’1.5 enter: ‘ + item.name); 

        setTimeout(function(){ 

            log(’1.5 handle: ‘ + item.name); 

            callback(null, item.name); 

        }, item.delay); 

    }, function(err) { 

        log(’1.5 err: ‘ + err); 

    });

     

    打印结果如下:

    42.247> 1.5 enter: Jack 

    42.248> 1.5 enter: Mike 

    42.351> 1.5 handle: Mike 

    42.352> 1.5 enter: Freewind 

    42.461> 1.5 handle: Jack 

    42.664> 1.5 handle: Freewind 

    42.664> 1.5 err: undefined

    可以看到前两个是同时开始的,而第三个是等前两个都完成以后才开始的。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/forEach.js

    2. map(arr, iterator(item, callback), callback(err, results))

    map的重点是转换,即把集合中的元素通过异步操作转为另一个对象,最后可以得到转换后的对象数组。它也提供了并行与顺序执行两种方式。

    这里给一个示例,给集合中的每个元素以异步方式增加!!!:

    var arr = [{name:'Jack', delay:200}, {name:'Mike', delay: 100}, {name:'Freewind', delay:300}, {name:'Test', delay: 50}];

    async.map(arr, function(item, callback) { 

        log(’1.1 enter: ‘ + item.name); 

        setTimeout(function() { 

            log(’1.1 handle: ‘ + item.name); 

            callback(null, item.name+’!!!’); 

        }, item.delay); 

    }, function(err,results) { 

        log(’1.1 err: ‘, err); 

        log(’1.1 results: ‘, results); 

    });

     

    打印结果如下:

    54.569> 1.1 enter: Jack 

    54.569> 1.1 enter: Mike 

    54.569> 1.1 enter: Freewind 

    54.569> 1.1 enter: Test 

    54.629> 1.1 handle: Test 

    54.679> 1.1 handle: Mike 

    54.789> 1.1 handle: Jack 

    54.879> 1.1 handle: Freewind 

    54.879> 1.1 err: 

    54.879> 1.1 results: [ 'Jack!!!', 'Mike!!!', 'Freewind!!!', 'Test!!!' ]

    可以看到,对各元素的操作是并行的,结果会汇总在一起交给最后的回调。

    如果想顺序执行,可使用mapSeries,它与map的用法一模一样。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/map.js

    3. filter(arr, iterator(item, callback(test)), callback(results))

    使用异步操作对集合中的元素进行筛选。需要注意的是,iterator的callback只有一个参数,只能接收true或false。

    对于出错,该函数没有做出任何处理,直接由nodejs抛出。所以需要注意对Error的处理。

    提供了并行与顺序执行两种方式。

    并行示例,找到所有>=3的元素:

    async.filter([1,2,3,4,5], function(item, callback) { 

        log(’1.1 enter: ‘ + item); 

        setTimeout(function() { 

            log(’1.1 test: ‘ + item); 

            callback(item>=3); 

        }, 200); 

    }, function(results) { 

        log(’1.1 results: ‘, results); 

    });

     

    打印结果如下:

    16.739> 1.1 enter: 1 

    16.749> 1.1 enter: 2 

    16.749> 1.1 enter: 3 

    16.749> 1.1 enter: 4 

    16.749> 1.1 enter: 5 

    16.749> 1.3 enter: 1 

    16.949> 1.1 test: 1 

    16.949> 1.1 test: 2 

    16.949> 1.1 test: 3 

    16.949> 1.1 test: 4 

    16.949> 1.1 test: 5 

    16.949> 1.1 results: [ 3, 4, 5 ]

    可见找到了满足条件的所有元素。

    如果需要顺序执行,可以使用filterSeries函数,它的用法与filter一样。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/filter_reject.js

    4. reject(arr, iterator(item, callback(test)), callback(results))

    reject与filter相似,只是行为正好相反。当条件为true时,它将丢弃相应的元素。它也提供了并行与顺序执行两种方式。

    并行示例,去掉所有>=3的元素:

    async.reject([1,2,3,4,5], function(item, callback) { 

        log(’1.4 enter: ‘ + item); 

        setTimeout(function() { 

            log(’1.4 test: ‘ + item); 

            callback(item>=3); 

        }, 200); 

    }, function(results) { 

        log(’1.4 results: ‘, results); 

    });

    打印结果如下:

    31.359> 1.4 enter: 1 

    31.359> 1.4 enter: 2 

    31.359> 1.4 enter: 3 

    31.359> 1.4 enter: 4 

    31.359> 1.4 enter: 5 

    31.559> 1.4 test: 1 

    31.559> 1.4 test: 2 

    31.559> 1.4 test: 3 

    31.559> 1.4 test: 4 

    31.559> 1.4 test: 5 

    31.569> 1.4 results: [ 1, 2 ]

    如果想顺序执行,可使用rejectSeries,它与reject用法一样。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/filter_reject.js

    5. reduce(arr, memo, iterator(memo,item,callback), callback(err,result))

    Reduce可以让我们给定一个初始值,用它与集合中的每一个元素做运算,最后得到一个值。reduce从左向右来遍历元素,如果想从右向左,可使用reduceRight。

    这里给个例子,计算出100与某个集合中所有数之和:

    var arr = [1,3,5];

    async.reduce(arr, 100, function(memo, item, callback) { 

        log(’1.1 enter: ‘ + memo +’, ‘ + item); 

        setTimeout(function() { 

            callback(null, memo+item); 

        }, 100); 

    },function(err, result) { 

        log(’1.1 err: ‘, err); 

        log(’1.1 result: ‘, result); 

    });

     

    将打印出结果:

    28.789> 1.1 enter: 100, 1 

    28.889> 1.1 enter: 101, 3 

    28.999> 1.1 enter: 104, 5 

    29.109> 1.1 err: 

    29.109> 1.1 result: 109

    需要注意的是,async中的reduce,不是并行操作,而是对元素一个个顺序操作,所以当元素比较多时,性能会比较弱。如果想提高性能,可使用async.map函数,先并行得到集合中每个元素被处理之后的值,然后再使用Array.prototype.reduce函数处理,性能会快很多。

    对于这个例子:

    async.reduce(arr, 100, function(memo,item,callback) { 

        log(’1.4 enter: ‘+memo+’,'+item); 

        t.inc(item, function(err,n) { 

            log(’1.4 handle: ‘,n); 

            callback(null, memo+n); 

        }); 

    }, function(err,result) { 

        log(’1.4 err: ‘, err); 

        log(’1.4 result: ‘, result); 

    });

     

    它总耗时为0.62秒。如果换成map+array.reduce:

    async.map(arr, function(item, callback) { 

        log(’1.5 enter: ‘, item); 

        t.inc(item, function(err,n){ 

            log(’1.5 handle: ‘, n); 

            callback(null,n); 

        });  

    },function(err, results) { 

        log(’1.5 err: ‘, err); 

        log(’1.5 results: ‘, results); 

        var sum = results.reduce(function(memo, item) { 

            return memo + item; 

        }, 100); 

        log(’1.5 sum: ‘, sum); 

    });

     

    耗时为0.21秒。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/reduce.js

    6. detect(array, iterator(item,callback(test)), callback(result)

    用于取得集合中满足条件的第一个元素。它分为并行与顺序执行两种方式,分别对应函数detect和detectSeries。

    并行示例,找到一个奇数:

    var arr = [{value:1,delay:500}, 

               {value:2,delay:200}, 

               {value:3,delay:300}]; 

    async.detect(arr, function(item,callback){ 

        log(’1.1 enter: ‘, item.value); 

        setTimeout(function() {

            log(’1.1 handle: ‘, item.value); 

            callback(n%2===1); 

        }, item.delay); 

    }, function(result) { 

        log(’1.1 result: ‘, result); 

    });

     

    结果如下:

    09.928> 1.1 enter: 1 

    09.928> 1.1 enter: 2 

    09.928> 1.1 enter: 3 

    10.138> 1.1 handle: 2 

    10.228> 1.1 handle: 3 

    10.228> 1.1 result: { value: 3, delay: 300 } 

    10.438> 1.1 handle: 1 

    10.438> 1.1 handle: 1

    可见得到了最先执行完的那个奇数3.

    更多详细示例:https://github.com/freewind/async_demo/blob/master/detect.js

    7. sortBy(array, iterator(item,callback(err,result)), callback(err,results))

    对集合内的元素进行排序,依据每个元素进行某异步操作后产生的值,从小到大排序。

    示例:

    var arr = [3,6,1];

    async.sortBy(arr, function(item, callback) { 

        setTimeout(function() { 

            callback(null,item); 

        }, 200); 

    }, function(err,results) { 

        log(’1.1 err: ‘, err); 

        log(’1.1 results: ‘, results); 

    });

     

    打印结果如下:

    26.562> 1.1 err: null 

    26.562> 1.1 results: [ 1, 3, 6 ]

    可以看到集合中的数据从小到大排好了序。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/sortBy.js

    8. some/any(arr, iterator(item,callback(test)), callback(result))

    当集合中是否有至少一个元素满足条件时,最终callback得到的值为true,否则为false。它有一个别名叫any。

    判断集合中是否有元素小于等于3:

    async.some([1,2,3,6], function(item,callback){ 

        log(’1.1 enter: ‘,item); 

        setTimeout(function(){ 

            log(’1.1 handle: ‘,item); 

            callback(item<=3); 

        },100);    

    }, function(result) { 

        log(’1.1 result: ‘, result); 

    });

    打印结果如下:

    36.165> 1.1 enter: 1 

    36.165> 1.1 enter: 2 

    36.165> 1.1 enter: 3 

    36.165> 1.1 enter: 6 

    36.275> 1.1 handle: 1 

    36.275> 1.1 result: true 

    36.275> 1.1 handle: 2 

    36.275> 1.1 handle: 3 

    36.275> 1.1 handle: 6

     

    可见的确得到了结果true。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/some.js

    9. every/all(arr, iterator(item,callback), callback(result))

    如果集合里每一个元素都满足条件,则传给最终回调的result为true,否则为false

    在下面的示例中,因为集合中每个元素都<=10,所以最终结果为true

    async.every(arr, function(item,callback){ 

        log(’1.1 enter: ‘,item); 

        setTimeout(function(){ 

            log(’1.1 handle: ‘,item); 

            callback(item<=10); 

        },100);    

    }, function(result) { 

        log(’1.1 result: ‘, result); 

    });

     

    打印如下:

    32.113> 1.1 enter: 1 

    32.123> 1.1 enter: 2 

    32.123> 1.1 enter: 3 

    32.123> 1.1 enter: 6 

    32.233> 1.1 handle: 1 

    32.233> 1.1 handle: 2 

    32.233> 1.1 handle: 3 

    32.233> 1.1 handle: 6 

    32.233> 1.1 result: true

    可见最终结果为true

    更多详细示例:https://github.com/freewind/async_demo/blob/master/every.js

    10. concat(arr, iterator(item,callback(err,result)), callback(err,result))

    将合并多个异步操作的结果合并为一个数组。

    在下面的示例中,将集合中的每一个元素都加倍:

    async.concat(['aa','bb'], function(item,callback) {

        setTimeout(function() {

            callback(null, [item, item]);

        }, 100);

    }, function(err, values) {

        log(’1.1 err: ‘, err);

        log(’1.1 values: ‘, values);

    });

    打印如下:

    13.539> 1.1 err:

    13.639> 1.1 values: [ 'aa', 'aa', 'bb', 'bb' ]

    打印出来的是经过合并后的数组。

    更多详细示例:https://github.com/freewind/async_demo/blob/master/concat.js

    展开全文
  • async函数

    千次阅读 2020-10-28 20:17:05
    async函数 async函数是什么 ECMAScript 2017规范引入了async 函数,该函数的主要目的就是简化使用 Promises, 异步调用的操作,并对一组Promises执行某些操作。正如 Promises 类似于结构化回调,async/await 类似于...
  • 之前翻看别的大佬的博客看到了关于setTimeout,promise还有async执行顺序的文章。观看了几篇之后还是没有怎么看懂,于是自己开始分析代码,并整理了此文章,我相信通过此文章朋友们能对异步同步还有,setTimeout,...
  • axios 进行同步请求(async+await)

    万次阅读 2019-04-27 16:46:56
    一般使用axios进行数据请求就是要使用异步请求,一些需求...如果一定要同步的话,async+await 了解一下? methods: { async funA(){ var res = await axios.post('') //这里的res就是axios请求回来的结果 } } ...
  • async function

    千次阅读 2019-11-13 10:05:50
    async function 声明定义了一个异步函数,它返回一个AsyncFunction对象。异步函数 是指通过 事件循环(event loop) 异步执行的函数,通过返回一个隐式的 Promise 作为其结果。使用异步函数的代码的语法和结构更像...
  • ES8之async函数

    万次阅读 2019-12-22 20:57:52
    什么是async函数 async 函数是什么?一句话,它就是 Generator 函数的语法糖。 基本用法 async函数返回一个 Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作...
  • async function async1() {console.log('async1 start');await async2();console.log('async1 end') 写出下边程序输出内容: async function async1() { console.log('async1 start'); await async2(); ...
  • async模块

    2018-08-09 17:04:58
    async是一个异步处理模块,主要有三个方式: 串行无关联 async.series() 并行无关联 async.parallel() 串行有关联 async.waterfall() 他们的基本用法,建一个a的文件夹,在它下面打开命令窗口,npm init 创建...
  • async with和async for

    万次阅读 2016-09-27 20:41:32
    网上async with和async for的中文资料比较少,我把PEP 492中的官方陈述翻译一下。异步上下文管理器”async with”异步上下文管理器指的是在enter和exit方法处能够暂停执行的上下文管理器。为了实现这样的功能,需要...
  • c# 非async方法调用async方法

    千次阅读 2019-04-18 17:33:45
    在C#中,强烈不建议非async方法调用async方法,建议一路async/await下去。如果一定要非async方法调用async方法,建议按照以下的优先级使用: 1. Task.Run(...).Result, 这种方式是新起了一个Task放在线程池中,参考...
  • async wait

    千次阅读 2018-03-14 15:37:08
    async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。即先执行asyncasync 函数返回的是一个 Promise 对象,然后进行await。async function doIt() { console.time("doIt");...
  • async 函数

    2019-03-24 14:51:14
    async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便。 async 函数是 Generator 函数的语法糖。 什么是语法糖? 意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。...
  • flutter函数中使用async,async使得函数异步执行。 1、async返回Stream,并通过yield关键字生成Stream流的值。 Stream<int> countForOneMinute() async* { for (int i = 1; i <= 60; i++) { await Future....
  • @Async

    2019-07-17 20:51:25
    @Async 作用:异步处理(多线程处理) 注意:1、SpringBoot 启动类加@EnableAsync ​ 2、异步方法加@Async注解 原理: ​ CGLib动态代理 ​ CGLIB是通过继承实现代理,也就是生成一个类继承被代理类;所以当你的...
  • 题目描述:写出执行结果,并解释原因(以...async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { console.log('async2'); } ...
  • async await

    千次阅读 2019-01-07 20:16:56
    随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await。我第一次看到这组关键字并不是在 JavaScript 语言里,而是在 c# 5.0 的语法中。C# 的 async/await 需要在 .NET Framework 4.5 ...
  • python async

    千次阅读 2019-05-26 17:38:00
    理解 python 的 async:1. 协程后面的技术也是 IO 多路复用, Nginx 和 nodejs 都充分利用了这种机制. 2. Flask 线程中为什么不能直接使用标准库 asyncio 来支持异步? asyncio 一定要有应该eventloop, 而这个 event...
  • async和await

    2020-05-03 22:10:00
    async和await是ES7出现关键字,目的是彻底解决回调地狱,比Promise彻底。即就是:把异步的回调变成了同步的写法。 据说,async和await是回调地狱的终极解决方案。 async:异步 await:等待 二、 async定义...
  • When can not find scala.async.Async.{async, await}, just add the following dependency to your pom.xml. <groupId>org.scala-lang.modules <artifactId>scala-asyn
  • async/await

    千次阅读 2020-03-31 12:26:17
    async/await async是ES7的与异步操作有关的关键字,其返回一个Promise对象,await操作符用于等待一个Promise对象,它只能在异步函数async function内部使用。 async 语法 async function name([param[, param[, ... ...

空空如也

1 2 3 4 5 ... 20
收藏数 108,875
精华内容 43,550
关键字:

async