How can i create a promise for the end of playing

2020-02-05 12:33发布

问题:

I have a simple JavaScript that loads sounds:

  prefix = 'modules/sounds/';
 _sounds = ['nameOfSound','nameOfSound','nameOfSound'];


 for (var sound in _sounds) {
                if (_sounds.hasOwnProperty(sound)) {
                    var cached = _sounds[sound];
                    cached.audio = new Audio(prefix + cached.src);
                    }
                }
            }

All is being cached here, and then in angular I just have a service that does the following function:

 this.play = function(trackName) {
        _sounds[trackName].audio.play();
    };

What I want is a simple promise for the sound, so when I call it, I will have something like this:

soundService.play('boom').then(function(){
    do something here
});

Is that even possible?

回答1:

You can make a generic object that you can implement to suit your setup:

function play(url) {
     return new Promise(function(resolve, reject) {   // return a promise
         var audio = new Audio();                     // create audio wo/ src
         audio.preload = "auto";                      // intend to play through
         audio.autoplay = true;                       // autoplay when loaded
         audio.onerror = reject;                      // on error, reject
         audio.onended = resolve;                     // when done, resolve

         audio.src = path + url + suffix; // just for example
     });
}

Now you can call:

play("boom").then(function() {

});

There is little point in caching audio elements due their buffering behavior. Indicating preload will tell browser that you will want to play through the audio file. In my opinion this is also nicer to the client and the system.

Example

function play(url) {
  return new Promise(function(resolve, reject) { // return a promise
    var audio = new Audio();                     // create audio wo/ src
    audio.preload = "auto";                      // intend to play through
    audio.autoplay = true;                       // autoplay when loaded
    audio.onerror = reject;                      // on error, reject
    audio.onended = resolve;                     // when done, resolve

    audio.src = url
  });
}

play(sample).then(function() {
  alert("Done!");
})
<script>
var sample = "data:audio/wav;base64,UklGRiAOAABXQVZFZm10IBAAAAABAAEA71YAAO9WAAABAAgAZGF0YfsNAACCgoKAgYKCgoKCgoGCgoGBgIB/foCAf35+fn19fX1+foCCgYGAgICAfn5+fnx8fn5/f3+AgICBgYKCg4OCgIB/fn5+gIB/gIGBgoGAf4CAgYB+fn5+fXx8fHx9fn59fX1+foB/f39+gIGAgIGBgIB+f4CAgICAgH+AgoKBgIGCgoKChYWBfHp5eHh5enx/goSGiYqMi4mHhoaEhIOCgH58fHx8fHx+fn5/gICAgYGCgoKDhIODgoCBgYCAgICAf319fn59fn5+fn+Afn6AgYCBgYCAf36AgICAgH5+f4CAgIB+fn59fHx+fn5/gYGBgoOEgoGBgYB+fn59f35+gIB+fn+AgICBgICAfn+AgICCgYCBgYGCgoKCgICBgH+AgICAgIGCgoGAgX9/foCAgICAgIB/gICAgYB+gIGCgoKCgICAf4CCg4KBgYCAfn6AgH99e3x9fXx8fH5/f4CAgICAgIGCgoOEgoKCg4OCgoKCgICAgICAgYKCgoKCgYCBgYKCgoKCgoCAgYF+fn5/gICAgH59foCAgX9+gIB+fX19fn+AgH5/f3+Afn19fX5/gICAf4CAgH59fX6AgH5+gICAf4CAgICAgYKBgoGAfn6AgICAgIKCgICAgICAf35+fn59fX1+fn6AgH9+gIGAf4CAgYCAgICBgYB/fn+Bg4F/foGDgn59gISEgn5+g4aFgX+AhIWEfnyBhoSAfH2Cg396en6Eg357foSGgXx9hIeEfnuAhoZ+en6FhoF7fYSIhH16foSCenl+g4R/eXuChX55eoCCfHd5foJ+enp+hIF6e4KEgXt7goWBe3yChoJ7fISGgXp8g4WAfH6Eh4F6fYSGgHp9hIaAe3+GhoB7gIeGfnyChoN8e4KGg3x6gYaBenyEhn95fISGfnp+h4Z8eH+Ggnl6goiAd3iEiIB4fImKgHh+h4R5cnmGhXdzfoiDd3aAioR4eYaMgnV3hoyCdXmJjoJ2fIqMfnR6jI5/c3uMjn50fo6PfnJ7jY18cnuMjnpteY6Oem14jI56bXmOjnprdo6Se2h0jZJ7Z3GOl4BmbIqZgmZqip2HZGeKn4plZIaklGlggqKWalp4nppxWXKdontZaZOkhFxhi6eTZlyApp5yWHGeq4RYXoqolGNVd6Gfc1ZrmauKXFuHrJtnU3Siq35TX5Cxll5Sfq6rck5ooLaNVliOuaNkTXKnsH1MW5K2m11JdKqxfkxalLiaWkh0rrV5RFaYwJ1VQXe3t3ZDW52+llFGfrq2ckBbnsGWUEaAtq9uQl6evJBORn60sXREXJy+l1NCdrO0dD9VmL6eWD5wsbl8QFGUvaJeQ26tvIRIU5C6pGNEaqa5jVBOhLWvckZfnLuZWkh1rLSCTlWKs6hxTmSXsZReTnKirINUVoSsqHhSYJGwmmhTb5uqjmFWeKKog1hZgKSieVZgiaWacllqkKiacVttk6eWcF1xlKSTcWBykqKRbV5xkqKSbVprkKWWbFRok6yYalFqmbCVYExtnrCQXE9wnrCTYlNznaqPY1Z0mqaOZFZylqKMZlpykp6MbmN0jZeMdWdziJKNem5zhI6LfXN2goqHfXZ3gIeEfnt7foCBgYF+fn1+goSDfXp8goeHfnd4gIiKgnZ1fomKgXZ2foeJgnd0e4SJhn54eoKKjYV4dX6KkYt6cXiGkIx7bXOGkpGAcHKElJOCb26Aj5GGdG55iY+KfXJ0g46QhHNteY2Uindsc4aSjHxvcICOj4FycXuIjId8dHN7iIyGe3N1go+OgXVweImPhnlwdIGLh313dHiEiYR9eHZ7hIeGgnlyeYmPh3tvcIGRjYBybXqMkYZ6cXOBjY6Ee3R2hJCPhndud4yWj31ra3+Wl4RvaXaNmIp3b3SBjo6Cd3V4gYmJhH53dHyKj4p+cG+AlJaFcmt1ipSKdWpteoqMgHVzeICIioJ8e3h8h46KgHd0fpCVjHxxcYGTk4Z4cXaGkIuAeHJ0gY+QhnZrboOXloNvZ3SMmpB6amp6kJaIdm5xe4qOh310bnWHk5CAbmZzjpqQeGZmepWciW5lbYGVmId1bnF+jZKIem5qdYyZkHtoZHWRoZV4Y2J3lqORcmFlfpyjjnJla4CYnYpyZ2p8k5uLc2hse5GajnpsaXaLmpJ4aGp4kJuQeWtreIyak35uaXGGmJeEbmhziZ2dhWxpc4ibm4VuaHSImZqGcGpyg5KWiHNtdH6Jkox7bm93hpOSfm5wfIaNjH91eoGAgYeJg317eXqFi4R7eHh5gYiHgX54cneFi4d+dG90go+Nf3Z0doCLioJ/fXd2fYeMi4FzbHSGlJKDcmhwhZWXiXRqbH6Tl4t7cGtyhpaXi3hoan6Wn5N4ZGN0jJqTfGllcIGTmot1bG96i5eSfnBveIWPkIV4dnuBg4aHhYF+enR3goyLgHJrcYSUkoJzc3uEiomCfX6Af32AiIyIgnp1eIKKjYh+dHJ4hpGRhHZvdYaQjoJ3dnyCgn6AgoODfnh3foSHhoB5dHR9h4uHfXRyd4GMj4R0bnaDjIp+eHqAhIWAenuAg4WEfnd1fIWLioB1cnqEi4yFenZ4foOFgn99fHt8foCBgoKCgXx5fIKEhYJ7d3p+goOCgH5+foCCgYCAgIOAfnx8gIOEhoN/foGFhoN9e36DhoR+en2ChYSAfX2Ag4KBgYKDgoB+gIKCgoGAgYKAfn6ChYR9en2ChoeBenuAhYSAfX6Ag4SAfX2AgoKCgH9+fX2Ag4KBfXp7goaDgH19gIKBfoCBgHt6fIGDgn58fYGCgH59gIKBfXt+gYKCfXl6foKEgXx5e4KGhoF8e4CEhIKAfXt+gYGChISBfXx+hIeFfnp8gYaHhYB9gIKDg4KBgYB+foCEhIB8enyEiod+eHqBiIiCenh+g4SBfnx8fXx7fICAfXp7foSGgXx8foKEgn59foGCgoGBgYKAgICBgoSEgn5+goeKhHx4eYCHiIN7eHqCiod+eHl9goWFgHt7fYCEhYJ7dniAhoWAenh6goeEfnt6fIKGhH15en2DhoJ9e3x+gYOCgH59fICCgYKAfHx9goSCgX17foKEgn56fICCgHx8fX6AgYB+fn5+fn6AgoJ+e3yAg4WEgH5+gYOCgH5+gH9+fn6ChIB6eHuAhoZ+eXp/hIeEfn2Ag4KAgYWGhIGAf4KFhoOBfnx+goSFhIB+fYCEhoSCgH6AgoSDgoCAgIGCg4OBfn1+gYKAfnt8foGBgH98fH+CgoB8enyAgoKAfXt+g4OBfnyAgoJ+fHyAg4N+ent+goOCf319fn+ChIF9e3x/gIGAgIB+fX2AgoWFgHp7foKDgn59fYGDhIOCgYKFhIKCgYCBg4OCgH2AhIaEgHx7foKEhH56e36ChISAfHyAg4WDgoKAfoCCgX99e3h5fICAfnt8f4KBgH9+gYSEgH5/goSFhoJ9fH+DhoV/enp+hIiHg318foGDhIJ/fX2AhoiFf3p4fIOGg3p0dn+GhoB5dnmAhIOAfn59foGEhIJ+fHx8gISFgn57fH6DhIJ+fHx/goSEgH19fYCBgICAgICAfHx+goSCfnx8foGDhIF+fH6BgoSCfnx8gISEgX58fH+CgoB+fH5/f4CAgIB/fH2AgoOAfXx+gIKCgH19foCDhYOAfn6Bg4SDgH5+gYOFgn59foGCg4OAfn5/goKCg4GAgIGChIJ/fH2Ag4WEgHp6foKGhHx4eX2DhIN/enp+goODgH18gIKBgYGAfn59foGBgH59fX5+foCCgn58fX6Bg4F9fH5+fn6CgoB+foCDhIF+foCCgoF+fn+BgoKAf4CBgYB/gIB/gIODhIKAfoCChISBfn1+gYODgn9+foCCgoB+fH5/gIB+fHyAgoOCfn1/gYOEgn5+gIGBgYGAfHx8fYCAfn18fICCgoF/foCBgoJ/fH2BhYaEgX9+gYWGg357fICEhoSBfn2AhIWFgn58fYCDhIF+fn6ChIOAf39+gYSCgH59foGCgH58fn+BgX98fICAgYB+fn5+f39+fn5+fX5+fn1+fn5/gH58fYB/fn18foGDgoCAgYKDg4B+fX2AgYCAgH9+foCBf4CBgICAgICBgICBgX9+fn+AgYGAfn2AgYKBf35+gIOCgYGAgoKCgoF+gYKCgoSAgYGBgoKDgYB+foB/f35/gICBgYCBgYGBgYGCgoKAgICChISCgH6AgoKCgH5/gIGBgYCBgH5/gYKAfn6AgIGAfX1/gYODgH18fICCgn58fHx9foCAfn18foB+foB+fn6AgH5/fn6AgoGAfoCAgIB+fn1+gIGBgH19foKEgn99foCChISDgH6AgYGCgX5+gICAgYF+fX1+gICCgoGAgIKDg4KDgoKDhISBf4CBg4WEgn5+gIKDg4B9fHt8fn6Afnt7foGCgoB+fYCCgoKCgIGBgoGBgIKCgoKCgoKCgYCCg4OEg4F/foCCgYGAgICBgYF+fn19fX1+fX19fYCCgoGBgH5+fn5/fn18foGBgH17e36Cg4F+fH6Ag4KAfX1/gYKCgYCAf4CAgICBgH9+f4CAgoKAfn6BgoKBgICAgIGAfn19fn19fHx9f4B+f39+fn6AgH59fXx9gIB+fn9/gICBgoKCgoGBgYKCgoKBgICAgYGBgICAgICBgYCBgoKBgICAgoKCgoGBgYKCgYGCg4KBgICAgYCBgoGAgIGCgoGAgICBg4KAgICBgoKCgH5+foCAgH5+foCCgYCAgH9/gYGAf358fH6Afn18foAA"
</script>



回答2:

You can write a service using $q.defer().

app.service('service', ['$q', function($q){
    this.play = function play(sound) {
        var deferred = $q.defer();
        sound.play();
        sound.onended = function(e) {
          deferred.resolve(e);
        }
        return deferred.promise;
    }
}]);

You can just call the service and expecting the promise return. service.play(sound).then(function(e){});

Full plunker sample - http://plnkr.co/edit/FJYjj4ehslqZQZmYyL1I?p=preview



回答3:

There is an 'ended' event that is emitted when the audio has finished playing. Source

 this.play = function(trackName) {
    return new Promise(function(resolve, reject) {
        var audio = _sounds[trackName].audio;
        audio.addEventListener('ended', resolve);
        audio.play();
    });
 };