Promise小结

Promise

由来

  假设存在一个名为createAudioFileAsync()的方法,这个方法通过一个参数以及两个回调函数创建一个声音文件,在声音文件成功创建或者创建失败后执行回调函数。

 function successCallback(result) {
   console.log("Audio file ready at URL: " + result);
 }

 function failureCallback(error) {
   console.log("Error generating audio file: " + error);
 }

 createAudioFileAsync(audioSettings, successCallback, failureCallback)

新式函数返回一个你可以直接绑定回调函数的promise对象,来代替旧式的函数形式:

  const promise = createAudioFileAsync(audioSettings);
  promise.then(successCallback, failureCallback);

  //更简单点
  createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
  <strong>我们把这个称为异步函数调用,这种形式有若干优点</strong>

优点: 链式调用

一个常见的需求就是连续执行两个或者多个异步操作,这种情况下,每一个后来的操作都在前面的操作执行成功之后,带着上一步操作所返回的结果开始执行。我们可以通过创造一个promise chain来完成这种需求。

基本上,每一个promise代表了链式中另一个异步过程的完成。

  // 经典的回调地狱
  doSomething(function(result) {
    doSomethingElse(result, function(newResult) {
      doThirdThing(newResult, function(finalResult) {
        console.log('Got the final result: ' + finalResult);
      }, failureCallback);
    }, failureCallback);
  }, failureCallback);

  // 新式函数
  doSomething().then(function(result) {
    return doSomethingElse(result);
  })
  .then(function(newResult) {
    return doThirdThing(newResult);
  })
  .then(function(finalResult) {
    console.log('Got the final result: ' + finalResult);
  })
  .catch(failureCallback);

  // 优化
  doSomething()
  .then(result => doSomethingElse(result))
  .then(newResult => doThirdThing(newResult))
  .then(finalResult => {
    console.log(`Got the final result: ${finalResult}`);
  })
  .catch(failureCallback);

Catch 的后续链式操作

  • 链式中的一个动作失败之后还能有助于新的动作继续完成
new Promise((resolve, reject) => {
  console.log('Initial');

  resolve();
})
.then(() => {
    throw new Error('Something failed');

    console.log('Do this');
})
.catch(() => {
    console.log('Do that');
})
.then(() => {
    console.log('Do this whatever happened before');
});

// Initial
// Do that
// Do this whatever happened before

catch(failureCallback) 是 then(null, failureCallback) 的缩略形式

错误传播

  doSomething()
  .then(result => doSomethingElse(value))
  .then(newResult => doThirdThing(newResult))
  .then(finalResult => console.log(`Got the final result: ${finalResult}`))
  .catch(failureCallback);

基本上,一个promise链式遇到异常就会停止,查看链式的底端,寻找catch处理程序来代替当前执行。在同步的代码执行之后,这是非常模型化的

try {
  let result = syncDoSomething();
  let newResult = syncDoSomethingElse(result);
  let finalResult = syncDoThirdThing(newResult);
  console.log(`Got the final result: ${finalResult}`);
} catch(error) {
  failureCallback(error);
}

在ECMAScript 2017标准的async/await语法糖中,这种同步形式代码的整齐性得到了极致的体现

async function foo() {
  try {
    let result = await doSomething();
    let newResult = await doSomethingElse(result);
    let finalResult = await doThirdThing(newResult);
    console.log(`Got the final result: ${finalResult}`);
  } catch(error) {
    failureCallback(error);
  }
}

在旧式回调API中创建Promise

有一些API仍然使用旧式的被传入的成功或者失败的回调
典型的例子就是setTimeout()函数:

  setTimeout(() => saySomething("10 seconds passed"), 10000);

混用旧式回调和promise是会有问题的。如果 saySomething 函数失败了或者包含了编程错误,那就没有办法捕获它了。

幸运的是我们可以用promise来包裹它。最好的做法是将有问题的函数包装在最低级别,并且永远不要再直接调用它们:

  const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
  wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);

时序 - 异步操作

  Promise.resolve(console.log(0)).then(() => console.log(2));
  console.log(1);

  // 0 1 2

  aFun = new Promise ((resolve) => {
    console.log('aFun')
    resolve()
  })
  function bFun () {
    console.log('bFun')
  }

  let promise = aFun.then(() => console.log('bFun'))
  promise
  console.log('promise ---')

  // aFun promise bFun

  let promise = async function promise () {
    await console.log('aFun')
    await console.log('bFun')
  }

  promise()
  console.log('promise ---')

  // aFun promise bFun

  await promise()
  console.log('promise----')

  // aFun bFun promise

原理分析

Promise中实现 值传递 Chain Promise

function Promise(fn) {
  var state = 'pending';
  var value;
  var deferred = null;

  function resolve(newValue) {
    console.log('resolve')
    value = newValue;
    state = 'resolved';

    if(deferred) {
      console.log('deferred')
      handle(deferred);
    }
  }

  function handle(handler) {
    if(state === 'pending') {
      deferred = handler;
      return;
    }

    if(!handler.onResolved) {
      handler.resolve(value);
      return;
    }

    var ret = handler.onResolved(value);
    handler.resolve(ret);
  }

  this.then = function(onResolved) {
    return new Promise(function(resolves) {
      console.log(resolves)
      handle({
        onResolved: onResolved,
        resolve: resolve
      });
    });
  };

  fn(resolve);
}

function doSomething () {
  return new Promise(function(resolve) {
    console.log('doSomeThing')
    var value = 42;
    resolve(value);
  });
}

doSomething().then(function(result) {
  console.log('first result', result);
  return 88;
}).then(function(secondResult) {
  console.log('second result', secondResult);
});
// * 所有操作都在doSomething 的 Promsie中操作.在第一个then时在Promise对象生成新的promise对象,第二个then在第一个生成的promise中操作
  进入 Promise(doSomething)
    生成 Promise(第一个then)
      生成 Promise(第二个then)
// 1. doSomething中 promise对象传入function进入Promise对象中,执行 fn(resolve) 执行到resolve(value)时,调用resolve方法
function fn (function resolve(value) {
    console.log('resolve')
    value = newValue;
    state = 'resolved';

    if(deferred) {
      handle(deferred);
    }
  })(42)
// 2. 赋值value到Promise对象的变量中
// 3. 调用this.then方法, 将
// function(result) {
//   console.log('first result', result);
//   return 88;
// }
// 作为参数传入then方法中,此时创建新的Promise(第一个then)
// 4. 调用handle方法,传入{ onResolved: onResolved, resolve: resolve }参数,此时resolve为Promise(doSomething)对象中的resolve方法
// 5. 在handle 中执行 var ret = handler.onResolved(value); 此时value为Promise(doSomething)对象的变量
//    因为resolve为Promise(doSomething)中的function,resolve中的value因为闭包的原因使得Promise(第一个then)中的value
//    指向Promise(doSomething)的value,value值被保留下来
// * 注意
//    此时的value不是this.value, this.value指向当前对象, 改为this.value后将会undefined,因为Promise(第一个then)对象的value申明但没有定义
// ret 为 then中return返回的88
// 6. 调用 handler.resolve(ret);将88赋值给value,返回新的Promise对象(第一个then)
// 7. 之后的then重复上述步骤
this.then = function (onResolved)
  return new Promise(function(resolve) {
      console.log(resolves)
      handle({
        onResolved: onResolved,
        resolve: resolve
      });
    }
)
posted @ 2018-10-17 17:56  Iven_Han  阅读(374)  评论(0编辑  收藏  举报