JavaScript · 异步之Promise

写在前面

本文内容及代码均摘取出自廖雪峰老师的JavaScript教程。
本文仅作为个人笔记,练习代码使用(所有的代码都需要自己手动敲上几遍),内容上也精简了很多。
相关知识还请阅读原文:Promise - JavaScript教程

Promise

promise是异步编程的一种解决方案,相比于传统解决方案callback更加的优雅。promise避免了“回调地狱”的产生。

待实现的需求:
函数执行,1s后输出pending,2s后输出finished

  • callback方式:
(function print() {
    setTimeout(function(){
        console.log('pending');
        setTimeout(function(){
            console.log('finished');
        },1000)
    },1000)
})()
  • promise方式:
function createPromise() {
    return new Promise(function(resolve,reject){
        setTimeout(resolve,1000)
    });
}

createPromise().then(function(){
    console.log('pending');
    return createPromise();
}).then(function(){
    console.log('finished');
})
  • ps:使用promise易犯的一个错误
let waitSecond = new Promise(function (resolve,reject){
    setTimeout(resolve,1000)
});
waitSecond.then(function(){
    console.log('pending');
    return waitSecond;
}).then(function(){
    console.log('finished');
})
// 1秒后,控制台同时输出'pending'和'finished'
// 这是因为同一个promise只能改变一次状态

这样来看,似乎promise的实现更复杂一些。但若场景再复杂化:请求test1,把请求结果作为参数去请求test2,以此类推

function request(url, param, successFun, errorFun) {
    $.ajax({
        type: 'GET',
        url: url,
        param: param,
        async: true,    //默认为true,即异步请求;false为同步请求
        success: successFun,
        error: errorFun
    });
}
  • callback方式(分步ajax请求)
request('test1.html', '', function(data1) {
    console.log('第一次请求成功, 这是返回的数据:', data1);
    request('test2.html', data1, function (data2) {
        console.log('第二次请求成功, 这是返回的数据:', data2);
        request('test3.html', data2, function (data3) {
            console.log('第三次请求成功, 这是返回的数据:', data3);
            //request... 继续请求
        }, function(error3) {
            console.log('第三次请求失败, 这是失败信息:', error3);
        });
    }, function(error2) {
        console.log('第二次请求失败, 这是失败信息:', error2);
    });
}, function(error1) {
    console.log('第一次请求失败, 这是失败信息:', error1);
});
  • promise方式(分步ajax请求)
function sendRequest(url, param) {
    return new Promise(function(resolve, reject) {
        request(url, param, resolve, reject);
    });
}

sendRequest('test1.html', '').then(function(data1) {
    console.log('第一次请求成功, 这是返回的数据:', data1);
    return sendRequest('test2.html', data1);
}).then(function(data2) {
    console.log('第二次请求成功, 这是返回的数据:', data2);
    return sendRequest('test3.html', data2);
}).then(function(data3) {
    console.log('第三次请求成功, 这是返回的数据:', data3);
}).catch(function(error) {
    //用catch捕捉前面的错误
    console.log('sorry, 请求失败了, 这是失败信息:', error);
});
promise 练习(结合setTimeout、DOM操作等)
  1. 生成一个0-2之间的随机数,如果大于1,则等待相应时间后返回成功,否则返回失败:
// 清除最近一次log:
var logging = document.getElementById('log-text');
while(logging.children.length > 0) {
    logging.removeChild(logging.children[logging.children.length - 1]);
}
// 输出结果到页面:
function log(text) {
    var p = document.createElement('p');
    p.innerText = text;
    logging.appendChild(p);
}
// 构建promise并执行
new Promise((resolve,reject) => {
    var timeOut = Math.random() * 2;
    log('timeOut:' + timeOut);
    if (timeOut > 1) {
        // 使用常规传参
        setTimeout(resolve,timeOut * 1000,'200 OK');
    } else {
        // 使用匿名函数
        setTimeout(() => {
            // log('do something');
            reject('setTimeout is: ' + timeOut )
        },timeOut * 1000);
        // 可见:使用匿名函数更灵活,比如在resolve、reject前调其他方法
    }
}).then((result) => {
    log('成功:' + result);
}).catch((reason) => {
    log('失败:' + reason);
})
  1. 串行执行一系列需要异步计算获得结果的任务,比如执行先平方,再求和,再平方:
// 清除最近一次log:
var logging = document.getElementById('log-text');
while(logging.children.length > 0) {
    logging.removeChild(logging.children[logging.children.length - 1]);
}
// 输出结果到页面:
function log(text) {
    var p = document.createElement('p');
    p.innerText = text;
    logging.appendChild(p);
}
// 返回promise的乘法运算
function multiply(input) {
    return new Promise((resolve,reject) => {
        log('Call multiply(): ');
        log('Calculate ' + input + ' x ' + input);
        setTimeout(resolve,1000,input * input);
    })
} 
// 返回promise的加法运算
function sum(input) {
    return new Promise((resolve,reject) => {
        log('Call sum(): ');
        log('Calculate ' + input + ' + ' + input);
        setTimeout(resolve,1000,input + input);
    })
}
new Promise((resolve,reject) => {
    log('start new Promise...');
    resolve(123);
}).then(multiply)
  .then(sum)
  .then(multiply)
  .then(sum)
  .then((result) => {
      log('The result is: ' + result)
  })

你可能感兴趣的:(javascript,es6)