kissy1.3的Promise精讲

标签: kissy | 发表时间:2013-07-07 15:01 | 作者:明河
出处:http://www.36ria.com

promise规范(留意明河这里用的是规范一词,也就是说Promise模块不止是kissy有,像jquery、dojo等著名js库都有,都是规范的具体实现)在现代javascript编程具有非常大的现实意义,特别是在NodeJs中,建议大家阅读《JavaScript异步编程》1-3章的内容,如果亲懒得买书,明河推荐阅读二篇经典文章: 《Javascript异步编程的4种方法》《JavaScript异步编程的Promise模式》

promise是commonJs的规范中的内容,目的是利用更为简洁良好的AP让异步处理过程更为通俗易懂,同时更为易用。

明河对promise价值理解是:promise消除反人类的多层回调嵌套,提高代码的可阅读性和可维护性。

promise典型场景应用

场景:需要发送三个异步请求,且三个异步请求存在依赖,写出来的代码可能如下:

KISSY.use('ajax',function(S,io){
    io.get('1.json',function(result1){
        io.get('2.json',function(result2){
            io.get('3.json',function(result3){

            })
        })
    })
})

“一不小心”亲就会写出这样的代码,然后请在深夜感受维护者的怨念….

多层嵌套回调是可维护性的大敌,反人类反自然,拿起promise,代表月亮消灭它们吧,少年~

来看下基于promise的改造。

KISSY.use('ajax',function(S,io){
    io.get('1.json').then(function(result1){
        //callback1
        return io.get('2.json');
    }).then(function(result2){
        //callback2
        return io.get('3.json');
    }).then(function(result3){
        //callback3
    })
})

通过代码的比较,你就会发现,基于Promise的代码,回调的多层嵌套已经消失,代码顿时清爽了很多,这一切多亏了 then(),代码更具有逻辑性,自然且方便理解。

(KISSY1.3的ajax模块继承于Promise.Defer()。)

再来看个 jsonp调用github api的demo,感受下Promise的用法。

Promise用法精讲

承玉曾写过一篇文章 promise api 与应用场景讲解了Promise的API设计。

明河这里主要讲解Promise的用法,相关API可以看 文档

Promise模块共有二个类: PromisePromise.Defer

假如Promise实例是岛屿的话,Defer实例就是岛屿间的吊桥,决定了Promise之间的链接和传递,来看个 最简单的demo

KISSY.use('node,promise',function(S,Node,Promise){
    var $ = Node.all;
    //实例化一个Defer,不用实例化Promise
    //Defer用于控制对应promise传递的成功和失败
    var d = new Promise.Defer();
    //promise是Defer的核心属性, 用于外部监听,传递成功/失败的函数
    var promise = d.promise;
    //then方法第一个参数监听异步链成功流转到此的值,返回新的promise,并向下传递
    promise.then(function (v) {
        return v + 1;
    }).then(function (v) {
        $('body').append('  

值为:'+v+',第二个then,值为第一个then中success回调的返回值。

'); }); //向异步链传值,并运转异步链 d.resolve(1); });

明河给代码加了详细的注释,请认真感受下promise api的使用。

(异步链是明河YY的名词,感觉比较切合promise的流转过程。)

首先创建Promise.Defer的实例:

    var d = new Promise.Defer();

获取promise属性(为一个Promise实例)。

        var promise = d.promise;

Promise有个核心方法: then(successCallback,failCallback),有二个参数:

  • successCallback:监听异步链成功流转到此的值,返回新的promise,并向下传递
  • failCallback:监听异步链失败流转到此的值,返回新的promise,并向下传递

大家想象下kissy中ajax的回调:

var ajax = io({
    type: 'post',
    url:url,
    dataType:'json'
})
ajax.then(function(result){
    S.log(result[0]);
},function(){
    S.log('服务器故障,请求失败!');
})

then()起到承上启下的作用,接收刘转过来的数据,同时向下传递数据。

回到demo:

promise.then(function (v) {
    return v + 1;
}).then(function (v) {
    $('body').append('  

值为:'+v+',第二个then,值为第一个then中success回调的返回值。

'); });

留意then回调的参数数据。

promise定义好了,并不执行,还需要Defer实例触发。

Defer有个resolve方法用于传递数据同时流转promise。

    d.resolve(1);

promise打破多层回调嵌套的用法

先看下 多个setTimeout的demo,感受下。

假设setTimeout嵌套逻辑如下:

setTimeout(function(){
    setTimeout(function(){
        setTimeout(function(){

        })
    })
})

有人写过这么变态的代码么…

现在,我们需要基于Promise进行改造。

KISSY.use('promise', function (S, Promise) {
        var d = new Promise.Defer();
        //向异步链传值,并运转异步链
        d.resolve(1);
        var promise = d.promise;
        //在setTimeout外包裹个promise
        promise.then(function (v) {
            var d = new Promise.Defer();
            setTimeout(function () {
                d.resolve(v + 1);
            }, 1000);
            return d.promise;
        })
        //特别留意这里,success的回调会等到上一个promise成功传递值到这里时触发
        .then(function (v) {
            alert('第二个then执行,异步链传到这里的值为'+v);
        });
    });

这个demo会比上一个复杂。

关键的代码是:

promise.then(function (v) {
    var d = new Promise.Defer();
    setTimeout(function () {
        d.resolve(v + 1);
    }, 1000);
    return d.promise;
})

then()可以返回个其他定义的Promise实例,一样可以保证异步链的流转,当内部定义的Defer,执行resolve(),后续的异步逻辑才往下执行。

组件继承于Promise

Promise切实地改变了异步组件的API,让用户更方便的demo。

典型的异步组件,像ajax和uploader。

严重建议大家,如果你写的组件是有异步逻辑的,请继承Promise,像下面的代码:

 KISSY.add(function(S,Promise){
     function IO(c) {
        var self = this;
        Promise.call(self);
     }
     S.mix(IO,{
        _defer: new Promise.Defer(this)
     })
     S.extend(IO, Promise,{

          _ioReady:function(){
                //成功获取数据后
                var defer = self._defer;
                defer[isSuccess ? 'resolve' : 'reject']([self.responseData, statusText, self]);
          }
     });
    return IO;
 },requires:['promise'])

总结

promise,是前端必须掌握的特性,严重推荐在日常编码中使用起来,改造下你的ajax代码,免得被人骂土鳖哦。

相关 [kissy1 promise] 推荐:

kissy1.3的Promise精讲

- - ria之家--RIA三部曲:jquery、ext、flex
promise是commonJs的规范中的内容,目的是利用更为简洁良好的AP让异步处理过程更为通俗易懂,同时更为易用. 明河对promise价值理解是:promise消除反人类的多层回调嵌套,提高代码的可阅读性和可维护性. promise典型场景应用. 场景:需要发送三个异步请求,且三个异步请求存在依赖,写出来的代码可能如下:.

Promise的前世今生和妙用技巧 - 破狼

- - 博客园_首页
JavaScript作为单线程运行于浏览器之中,这是每本JavaScript教科书中都会被提到的. 同时出于对UI线程操作的安全性考虑,JavaScript和UI线程也处于同一个线程中. 因此对于长时间的耗时操作,将会阻塞UI的响应. 为了更好的UI体验,应该尽量的避免JavaScript中执行较长耗时的操作(如大量for循环的对象diff等)或者是长时间I/O阻塞的任务.

从事件驱动到observable的异步编程——PubSub+Promise+Rx的JS事件库

- Kejun - YY in Limbo 混沌海狂想
你上当叻,虽然从外面看标题很有气势,传达出一种宏大叙事的赶脚,其实我只是刚刚把一个阿尔法城的JS模块提交到github,想顺便介绍一下,但我连API文档都懒得写,就别指望能深入浅出的讲一遍来龙去脉了⋯⋯. 所以就直接帖几个前置阅读的链接罢. 这些潮流的外部起源:(技术也有外源论/exogenesis⋯⋯).